Skip to content

Commit 823b295

Browse files
author
itpey
committed
init
1 parent 92b7df3 commit 823b295

File tree

10 files changed

+807
-0
lines changed

10 files changed

+807
-0
lines changed

app/cli.go

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// Copyright 2024 itpey
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package app
16+
17+
import (
18+
"fmt"
19+
"os"
20+
"path/filepath"
21+
22+
"github.com/fatih/color"
23+
"github.com/urfave/cli/v2"
24+
)
25+
26+
func Create() *cli.App {
27+
app := &cli.App{
28+
Name: "figo",
29+
Usage: "A CLI tool for rapidly scaffolding new Go projects",
30+
Description: appDescription,
31+
Copyright: appCopyright,
32+
Authors: appAuthors,
33+
Version: appVersion,
34+
Action: func(c *cli.Context) error {
35+
clearConsole()
36+
fmt.Print(color.HiMagentaString(appNameArt))
37+
38+
var projectName string
39+
40+
for {
41+
projectName = promptProjectName()
42+
if projectName == "" {
43+
fmt.Println(color.RedString("Error: project name cannot be empty"))
44+
continue
45+
}
46+
47+
if !isValidProjectName(projectName) {
48+
fmt.Println(color.RedString("Error: invalid project name: %s\n", projectName))
49+
continue
50+
}
51+
break
52+
}
53+
54+
templates, err := listTemplates()
55+
if err != nil {
56+
return err
57+
}
58+
59+
if len(templates) == 0 {
60+
return fmt.Errorf(color.RedString("Error: no templates found in", templatesDirectory))
61+
}
62+
63+
selectedTemplate, err := selectTemplate(templates)
64+
if err != nil {
65+
return err
66+
}
67+
68+
createProject(projectName, selectedTemplate)
69+
return nil
70+
},
71+
Commands: []*cli.Command{
72+
{
73+
Name: "doctor",
74+
Usage: "Check system environment for Git and Go",
75+
Aliases: []string{"doc"},
76+
Action: func(c *cli.Context) error {
77+
return runDoctor()
78+
},
79+
},
80+
{
81+
Name: "create",
82+
Aliases: []string{"init", "new", "i", "c"},
83+
Usage: "Create a new Go project",
84+
Action: func(c *cli.Context) error {
85+
return createProject(c.String("name"), c.String("template"))
86+
},
87+
Flags: []cli.Flag{
88+
&cli.StringFlag{
89+
Name: "name",
90+
Aliases: []string{"n"},
91+
Usage: "Name of the project",
92+
Required: true,
93+
},
94+
95+
&cli.StringFlag{
96+
Name: "template",
97+
Aliases: []string{"t"},
98+
Usage: "Project template to use",
99+
Value: "default",
100+
},
101+
},
102+
},
103+
{
104+
Name: "list-templates",
105+
Aliases: []string{"lt", "ls", "l"},
106+
Usage: "List available figo project templates",
107+
Action: func(c *cli.Context) error {
108+
109+
templates, err := listTemplates()
110+
if err != nil {
111+
return err
112+
}
113+
114+
if len(templates) == 0 {
115+
return fmt.Errorf(color.RedString("Error: no templates found in", templatesDirectory))
116+
}
117+
118+
fmt.Println(color.YellowString("Available templates:"))
119+
printTemplateOptions(templates, -1)
120+
return nil
121+
122+
},
123+
},
124+
{
125+
Name: "add-templates",
126+
Aliases: []string{"add"},
127+
Usage: "Download figo project templates from a Git repository",
128+
Flags: []cli.Flag{
129+
&cli.StringFlag{
130+
Name: "url",
131+
Aliases: []string{"u"},
132+
Usage: "Git repository URL to download templates from",
133+
},
134+
},
135+
Action: func(c *cli.Context) error {
136+
url := c.String("url")
137+
return downloadTemplates(url)
138+
139+
},
140+
},
141+
{
142+
Name: "delete-templates",
143+
Aliases: []string{"del"},
144+
Usage: "Delete figo project templates",
145+
Flags: []cli.Flag{
146+
&cli.StringFlag{
147+
Name: "name",
148+
Aliases: []string{"n"},
149+
Required: true,
150+
Usage: "Delete a specific figo project template by name",
151+
Action: func(c *cli.Context, name string) error {
152+
return deleteTemplateByName(name)
153+
},
154+
},
155+
},
156+
Subcommands: []*cli.Command{
157+
{
158+
Name: "all",
159+
Usage: "Delete all figo project templates",
160+
Action: func(c *cli.Context) error {
161+
return deleteAllTemplates()
162+
},
163+
},
164+
},
165+
},
166+
{
167+
Name: "version",
168+
Aliases: []string{"v", "ver", "about"},
169+
Usage: "Print the version",
170+
Action: func(c *cli.Context) error {
171+
return showVersion()
172+
},
173+
},
174+
},
175+
}
176+
177+
return app
178+
}
179+
180+
func createProject(projectName string, templateName string) error {
181+
fmt.Print(color.YellowString("Creating project '%s'...\n", projectName))
182+
183+
templatePath := filepath.Join(templatesDirectory, templateName)
184+
185+
if _, err := os.Stat(templatePath); err != nil {
186+
return fmt.Errorf(color.RedString("Error: template '%s' not found", templateName))
187+
}
188+
189+
projectPath := filepath.Join(".", projectName)
190+
191+
// Create project directory
192+
if err := os.MkdirAll(projectPath, 0755); err != nil {
193+
return fmt.Errorf(color.RedString("Error: creating project directory: %v", err))
194+
}
195+
196+
// Copy project from template directory to project directory
197+
if err := copyTemplate(templatePath, projectPath, true); err != nil {
198+
return fmt.Errorf(color.RedString("Error: copying project: %v", err))
199+
}
200+
201+
// Initialize Git repository
202+
if err := initializeGitRepository(projectPath); err != nil {
203+
return fmt.Errorf(color.RedString("Error: initializing Git repository: %v", err))
204+
}
205+
206+
// Run 'go get' to fetch dependencies (if any)
207+
if err := runGoGet(projectPath); err != nil {
208+
return fmt.Errorf(color.RedString("Error: running 'go get': %v", err))
209+
}
210+
211+
// Run 'go mod tidy' to clean up go.mod and go.sum files
212+
if err := runGoModTidy(projectPath); err != nil {
213+
return fmt.Errorf(color.RedString("Error: running 'go mod tidy': %v", err))
214+
}
215+
216+
fmt.Print(color.GreenString("Project '%s' created successfully!\n", projectName))
217+
218+
return nil
219+
}

app/constants.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2024 itpey
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package app
16+
17+
import "github.com/urfave/cli/v2"
18+
19+
const (
20+
appNameArt = `______________
21+
___ ____/__(_)______ ______
22+
__ /_ __ /__ __ / __ \
23+
_ __/ _ / _ /_/ // /_/ /
24+
/_/ /_/ _\__, / \____/
25+
/____/ ` + "\n\n"
26+
appVersion = "0.1.0"
27+
appDescription = `Figo is a command-line interface (CLI) tool designed to streamline the process of creating new Go projects.
28+
With figo, you can quickly scaffold out the directory structure, configuration files, and necessary boilerplate code for your Go applications.`
29+
appCopyright = "Apache-2.0 license\nFor more information, visit the GitHub repository: https://github.com/itpey/figo"
30+
defaultTemplatesRepoURL = "https://github.com/itpey/figo-templates"
31+
32+
metaDataDirectoryname = "figo"
33+
metadataFileName = "figo.json"
34+
)
35+
36+
var (
37+
templatesDirectory = getDefaultDirectory("templates")
38+
repoDirectory = getDefaultDirectory("repo")
39+
)
40+
var (
41+
appAuthors = []*cli.Author{{Name: "itpey", Email: "itpey@github.com"}}
42+
)

app/doctor.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package app
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
7+
"github.com/fatih/color"
8+
)
9+
10+
func runDoctor() error {
11+
12+
// Check Git version
13+
gitVersionCmd := exec.Command("git", "--version")
14+
gitVersionOutput, err := gitVersionCmd.CombinedOutput()
15+
if err != nil {
16+
fmt.Print(color.RedString("Error: git is not installed or not available in PATH"))
17+
} else {
18+
fmt.Print(color.GreenString(string(gitVersionOutput)))
19+
}
20+
21+
// Check Go version
22+
goVersionCmd := exec.Command("go", "version")
23+
goVersionOutput, err := goVersionCmd.CombinedOutput()
24+
if err != nil {
25+
fmt.Print(color.RedString("Error: go is not installed or not available in PATH"))
26+
} else {
27+
fmt.Print(color.GreenString(string(goVersionOutput)))
28+
}
29+
30+
// Check if both Git and Go are available
31+
if err == nil {
32+
fmt.Println(color.GreenString("All required tools are installed and accessible."))
33+
fmt.Print(color.YellowString("Run 'figo help' for usage instructions."))
34+
} else {
35+
fmt.Println(color.RedString("Error: system environment check completed with errors."))
36+
fmt.Print(color.YellowString("Please ensure that Git and Go are installed and available in your PATH."))
37+
}
38+
39+
return nil
40+
}

0 commit comments

Comments
 (0)