Skip to content

Commit 70a1170

Browse files
committed
make:package command supports generating a manager
1 parent 72f4028 commit 70a1170

File tree

4 files changed

+163
-15
lines changed

4 files changed

+163
-15
lines changed

foundation/console/package_make_command.go

+16-6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ func (r *PackageMakeCommand) Extend() command.Extend {
3131
return command.Extend{
3232
Category: "make",
3333
Flags: []command.Flag{
34+
&command.BoolFlag{
35+
Name: "manager",
36+
Aliases: []string{"m"},
37+
Usage: "Create a package manager",
38+
DisableDefaultText: true,
39+
},
3440
&command.StringFlag{
3541
Name: "root",
3642
Aliases: []string{"r"},
@@ -72,12 +78,16 @@ func (r *PackageMakeCommand) Handle(ctx console.Context) error {
7278
packageName := packageName(pkg)
7379
packageMakeCommandStubs := NewPackageMakeCommandStubs(pkg, root)
7480
files := map[string]func() string{
75-
"README.md": packageMakeCommandStubs.Readme,
76-
"service_provider.go": packageMakeCommandStubs.ServiceProvider,
77-
packageName + ".go": packageMakeCommandStubs.Main,
78-
"config/" + packageName + ".go": packageMakeCommandStubs.Config,
79-
"contracts/" + packageName + ".go": packageMakeCommandStubs.Contracts,
80-
"facades/" + packageName + ".go": packageMakeCommandStubs.Facades,
81+
"README.md": packageMakeCommandStubs.Readme,
82+
"service_provider.go": packageMakeCommandStubs.ServiceProvider,
83+
packageName + ".go": packageMakeCommandStubs.Main,
84+
filepath.Join("config", packageName+".go"): packageMakeCommandStubs.Config,
85+
filepath.Join("contracts", packageName+".go"): packageMakeCommandStubs.Contracts,
86+
filepath.Join("facades", packageName+".go"): packageMakeCommandStubs.Facades,
87+
}
88+
89+
if ctx.OptionBool("manager") {
90+
files[filepath.Join("manager", "manager.go")] = packageMakeCommandStubs.Manager
8191
}
8292

8393
for path, content := range files {

foundation/console/package_make_command_stubs.go

+97
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,100 @@ func DummyCamelName() contracts.DummyCamelName {
122122

123123
return content
124124
}
125+
126+
func (r PackageMakeCommandStubs) Manager() string {
127+
content := `package main
128+
129+
import (
130+
"os"
131+
"path"
132+
"path/filepath"
133+
"runtime/debug"
134+
"strings"
135+
136+
pkgcontracts "github.com/goravel/framework/contracts/packages"
137+
"github.com/goravel/framework/packages"
138+
"github.com/goravel/framework/support/color"
139+
)
140+
141+
var (
142+
module string
143+
dir string
144+
force bool
145+
)
146+
147+
func init() {
148+
for i, arg := range os.Args {
149+
if arg == "--force" || arg == "-f" {
150+
force = true
151+
}
152+
153+
if (arg == "--dir" || arg == "-d") && len(os.Args) > i+1 {
154+
dir = os.Args[i+1]
155+
}
156+
}
157+
158+
if info, ok := debug.ReadBuildInfo(); ok && strings.HasSuffix(info.Path, "manager") {
159+
module = path.Dir(info.Path)
160+
}
161+
162+
if dir == "" {
163+
dir, _ = os.Getwd()
164+
}
165+
}
166+
167+
func main() {
168+
var pkg = packages.Manager{
169+
ContinueOnError: force,
170+
Module: module,
171+
OnInstall: []pkgcontracts.FileModifier{
172+
packages.ModifyGoFile{
173+
File: filepath.Join("config", "app.go"),
174+
Modifiers: []pkgcontracts.GoNodeModifier{
175+
packages.AddImportSpec(module),
176+
packages.AddProviderSpec(
177+
"&DummyName.ServiceProvider{}",
178+
),
179+
},
180+
},
181+
},
182+
OnUninstall: []pkgcontracts.FileModifier{
183+
packages.ModifyGoFile{
184+
File: filepath.Join("config", "app.go"),
185+
Modifiers: []pkgcontracts.GoNodeModifier{
186+
packages.RemoveImportSpec(module),
187+
packages.RemoveProviderSpec("&DummyName.ServiceProvider{}"),
188+
},
189+
},
190+
},
191+
}
192+
193+
if module == "" {
194+
color.Errorln("package module name is empty, please run command with module name.")
195+
return
196+
}
197+
198+
if len(os.Args) > 1 && os.Args[1] == "install" {
199+
err := pkg.Install(dir)
200+
if err != nil {
201+
color.Errorln(err)
202+
return
203+
}
204+
color.Successln(module, " package installed successfully.")
205+
}
206+
207+
if len(os.Args) > 1 && os.Args[1] == "uninstall" {
208+
err := pkg.Uninstall(dir)
209+
if err != nil {
210+
color.Errorln(err)
211+
return
212+
}
213+
color.Successln(module, " package uninstalled successfully.")
214+
}
215+
}
216+
217+
`
218+
content = strings.ReplaceAll(content, "DummyName", r.name)
219+
220+
return content
221+
}

foundation/console/package_make_command_test.go

+38-6
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ func (s *PackageMakeCommandTestSuite) TestExtend() {
4242

4343
if len(got.Flags) > 0 {
4444
s.Run("should have correctly configured StringFlag", func() {
45-
flag, ok := got.Flags[0].(*command.StringFlag)
45+
managerFlag, ok := got.Flags[0].(*command.BoolFlag)
46+
if !ok {
47+
s.Fail("First flag is not BoolFlag (got type: %T)", got.Flags[0])
48+
}
49+
50+
rootFlag, ok := got.Flags[1].(*command.StringFlag)
4651
if !ok {
4752
s.Fail("First flag is not StringFlag (got type: %T)", got.Flags[0])
4853
}
@@ -52,10 +57,13 @@ func (s *PackageMakeCommandTestSuite) TestExtend() {
5257
got interface{}
5358
expected interface{}
5459
}{
55-
{"Name", flag.Name, "root"},
56-
{"Aliases", flag.Aliases, []string{"r"}},
57-
{"Usage", flag.Usage, "The root path of package, default: packages"},
58-
{"Value", flag.Value, "packages"},
60+
{"Name", rootFlag.Name, "root"},
61+
{"Aliases", rootFlag.Aliases, []string{"r"}},
62+
{"Usage", rootFlag.Usage, "The root path of package, default: packages"},
63+
{"Value", rootFlag.Value, "packages"},
64+
{"Name", managerFlag.Name, "manager"},
65+
{"Aliases", managerFlag.Aliases, []string{"m"}},
66+
{"Usage", managerFlag.Usage, "Create a package manager"},
5967
}
6068

6169
for _, tc := range testCases {
@@ -93,10 +101,32 @@ func (s *PackageMakeCommandTestSuite) TestHandle() {
93101
},
94102
},
95103
{
96-
name: "name is sms and use default root",
104+
name: "name is sms and use default root(hasn't manager)",
105+
setup: func() {
106+
mockContext.EXPECT().Argument(0).Return("sms").Once()
107+
mockContext.EXPECT().Option("root").Return("packages").Once()
108+
mockContext.EXPECT().OptionBool("manager").Return(false).Once()
109+
mockContext.EXPECT().Success("Package created successfully: packages/sms").Once()
110+
},
111+
assert: func() {
112+
s.NoError(NewPackageMakeCommand().Handle(mockContext))
113+
s.True(file.Exists("packages/sms/README.md"))
114+
s.True(file.Exists("packages/sms/service_provider.go"))
115+
s.True(file.Exists("packages/sms/sms.go"))
116+
s.True(file.Exists("packages/sms/config/sms.go"))
117+
s.True(file.Exists("packages/sms/contracts/sms.go"))
118+
s.True(file.Exists("packages/sms/facades/sms.go"))
119+
s.True(file.Contain("packages/sms/facades/sms.go", "goravel/packages/sms"))
120+
s.True(file.Contain("packages/sms/facades/sms.go", "goravel/packages/sms/contracts"))
121+
s.NoError(file.Remove("packages"))
122+
},
123+
},
124+
{
125+
name: "name is sms and use default root(has manager)",
97126
setup: func() {
98127
mockContext.EXPECT().Argument(0).Return("sms").Once()
99128
mockContext.EXPECT().Option("root").Return("packages").Once()
129+
mockContext.EXPECT().OptionBool("manager").Return(true).Once()
100130
mockContext.EXPECT().Success("Package created successfully: packages/sms").Once()
101131
},
102132
assert: func() {
@@ -109,6 +139,7 @@ func (s *PackageMakeCommandTestSuite) TestHandle() {
109139
s.True(file.Exists("packages/sms/facades/sms.go"))
110140
s.True(file.Contain("packages/sms/facades/sms.go", "goravel/packages/sms"))
111141
s.True(file.Contain("packages/sms/facades/sms.go", "goravel/packages/sms/contracts"))
142+
s.True(file.Exists("packages/sms/manager/manager.go"))
112143
s.NoError(file.Remove("packages"))
113144
},
114145
},
@@ -117,6 +148,7 @@ func (s *PackageMakeCommandTestSuite) TestHandle() {
117148
setup: func() {
118149
mockContext.EXPECT().Argument(0).Return("github.com/goravel/sms-aws").Once()
119150
mockContext.EXPECT().Option("root").Return("package").Once()
151+
mockContext.EXPECT().OptionBool("manager").Return(false).Once()
120152
mockContext.EXPECT().Success("Package created successfully: package/github_com_goravel_sms_aws").Once()
121153
},
122154
assert: func() {

packages/helper.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ func AddConfigSpec(path, name, statement string) packages.GoNodeModifier {
6666

6767
// AddImportSpec adds an import statement to the file.
6868
func AddImportSpec(path string, name ...string) packages.GoNodeModifier {
69+
matcher := MatchLastOf(MatchTypeOf(&dst.ImportSpec{}))
70+
if isThirdParty(path) {
71+
matcher = MatchTypeOf(&dst.ImportSpec{})
72+
}
73+
6974
return ModifyGoNode{
70-
Matchers: []packages.GoNodeMatcher{
71-
MatchTypeOf(&dst.ImportSpec{}),
72-
},
75+
Matchers: []packages.GoNodeMatcher{matcher},
7376
Action: func(cursor *dstutil.Cursor) {
7477
im := &dst.ImportSpec{
7578
Path: &dst.BasicLit{
@@ -198,3 +201,9 @@ func providerSpecInsertTo(matchers []packages.GoNodeMatcher, statement string, b
198201
},
199202
}
200203
}
204+
205+
func isThirdParty(importPath string) bool {
206+
// Third party package import path usually contains "." (".com", ".org", ...)
207+
// This logic is taken from golang.org/x/tools/imports package.
208+
return strings.Contains(importPath, ".")
209+
}

0 commit comments

Comments
 (0)