我需要为每种构建类型创建构建器(基础)和特定的构建器。
e.g. builder for html project builder for node.js project builder for python project builder for java project
…。
主要功能如下:
File:Builder.go
接口
type Builder interface { Build(string) error }
文件:nodebuilder.go
//This is the struct ???? not sure what to put here... type Node struct { } func (n Node) Build(path string) error { //e.g. Run npm install which build's nodejs projects command := exec.Command("npm", "install") command.Dir = “../path2dir/“ Combined, err := command.CombinedOutput() if err != nil { log.Println(err) } log.Printf("%s", Combined) } ... //return new(error) }
主要假设/过程:
mvn build
npm install
注意:除了build和之后path(应专门处理),所有其他功能都相同, 例如 zip copy
build
path
zip
copy
我应该将放置在zip and copy(结构中)的哪个位置,例如,应该如何实现它们并将它们传递给构建器? 我是否应该根据假设对项目进行结构设计?
我应该将放置在zip and copy(结构中)的哪个位置,例如,应该如何实现它们并将它们传递给构建器?
zip and copy
我是否应该根据假设对项目进行结构设计?
SOLID 的第一条原则说一段代码应该只承担一个责任。
发生在该背景下,它确实是没有意义的,任何builder关心copy和zip构建过程的一部分。这超出了builder责任。即使使用合成(嵌入)也不够整洁。
builder
Builder顾名思义,缩小范围,其核心职责是构建代码。但更具体地说,Builder的责任是在路径上构建代码。什么路 最惯用的方法是 当前路径 , 工作目录 。这会在接口中添加两个方法:Path() string返回 当前路径 和ChangePath(newPath string) error更改 当前路径 。该方法很简单,保留一个字符串字段,因为当前路径通常可以完成此工作。而且它可以轻松地扩展到某些远程过程。
Builder
Path() string
ChangePath(newPath string) error
如果我们仔细地看一下,这无疑是两个 构建 概念。一个是整个构建 过程 ,从制作temp目录到将其复制回去,全部五个步骤。另一个是build 命令 ,这是该过程的第三步。
那是非常鼓舞人心的。就像传统的程序编程一样,过程是作为功能呈现的过程。因此,我们编写了一个Build函数。它序列化了所有5个步骤,简单而又简单。
Build
码:
package main import ( "io/ioutil" ) //A builder is what used to build the language. It should be able to change working dir. type Builder interface { Build() error //Build builds the code at current dir. It returns an error if failed. Path() string //Path returns the current working dir. ChangePath(newPath string) error //ChangePath changes the working dir to newPath. } //TempDirFunc is what generates a new temp dir. Golang woould requires it in GOPATH, so make it changable. type TempDirFunc func() string var DefualtTempDirFunc = func() string { name,_ := ioutil.TempDir("","BUILD") return name } //Build builds a language. It copies the code to a temp dir generated by mkTempdir //and call the Builder.ChangePath to change the working dir to the temp dir. After //the copy, it use the Builder to build the code, and then zip it in the tempfile, //copying the zip file to `toPath`. func Build(b Builder, toPath string, mkTempDir TempDirFunc) error { if mkTempDir == nil { mkTempDir = DefaultTempDirFunc } path,newPath:=b.Path(),mkTempDir() defer removeDir(newPath) //clean-up if err:=copyDir(path,newPath); err!=nil { return err } if err:=b.ChangePath(newPath) !=nil { return err } if err:=b.Build(); err!=nil { return err } zipName,err:=zipDir(newPath) // I don't understand what is `dep`. if err!=nil { return err } zipPath:=filepath.Join(newPath,zipName) if err:=copyFile(zipPath,toPath); err!=nil { return err } return nil } //zipDir zips the `path` dir and returns the name of zip. If an error occured, it returns an empty string and an error. func zipDir(path string) (string,error) {} //All other funcs is very trivial.
大部分的东西都涵盖在评论,我真的很砍伐懒得所有写那些copyDir/ removeDir东西。在设计部分中没有提到的一件事是mkTempDir功能。如果代码位于/tmp/xxx/之外GOPATH,那么Golang会感到不满意,并且由于更改代码GOPATH会破坏导入路径服务,因此更改时会遇到更多麻烦,因此golang需要使用唯一的函数才能在中生成临时目录GOPATH。
copyDir
removeDir
mkTempDir
/tmp/xxx/
GOPATH
编辑:
哦,我忘了说一件事。像这样处理错误是非常丑陋和不负责任的。但是这个想法就在那里,而且更体面的错误处理主要需要使用内容。因此,请自己进行更改,记录日志,出现紧急情况或您想要的任何内容。
编辑2:
您可以按以下方式重新使用您的npm示例。
type Node struct { path string } func (n Node) Build(path string) error { //e.g. Run npm install which build's nodejs project command := exec.Command("npm", "install") command.Dir = n.path Combined, err := command.CombinedOutput() if err != nil { log.Println(err) } log.Printf("%s", Combined) return nil } func (n *Node) ChangePath(newPath string) error { n.path = newPath } func (n Node) Path() string { return n.path }
并将其与其他语言结合在一起:
func main() { path := GetPathFromInput() switch GetLanguageName(path) { case "Java": Build(&Java{path},targetDirForJava(),nil) case "Go": Build(&Golang{path,cgoOptions},targetDirForGo(),GoPathTempDir()) //You can disable cgo compile or something like that. case "Node": Build(&Node{path},targetDirForNode(),nil) } }
一种技巧是获取语言名称。GetLanguageName应该返回代码path所使用的语言的名称。这可以通过使用ioutil.ReadDir检测文件名来完成。
GetLanguageName
ioutil.ReadDir
还要注意,尽管我使Node结构非常简单,只存储一个path字段,但是您可以轻松扩展它。就像Golang部分一样,您可以在此处添加构建选项。
Node
Golang
编辑3:
关于包装结构:
首先,我实际上认为所有内容:Build函数,语言构建器和其他util / helpers应该放在一个包中。它们都是为一项任务而工作:建立一种语言。没有必要,几乎没有期望将任何代码段隔离为另一个(子)程序包。
因此,这意味着一个目录。剩下的确实是一些非常个人化的风格,但我会分享我的:
我会将函数Build和接口Builder放入一个名为的文件中main.go。如果前端代码极少且可读性强,我也会将它们放入其中main.go,但是如果前端代码很长且具有某些ui逻辑,则根据实际代码将其放入front- end.goor cli.go或ui.goor中。
main.go
front- end.go
cli.go
ui.go
接下来,对于每种语言,我将.go使用语言代码创建一个文件。这清楚表明我可以在哪里检查它们。或者,如果代码真的很小,那么将它们全部组合到一个中也不是坏主意builders.go。毕竟,现代编辑器不仅仅具有定义结构和类型的能力。
.go
builders.go
最后,所有的copyDir,zipDir功能都到了util.go。这很简单-它们是实用程序,大多数时候我们只是不想打扰它们。
zipDir
util.go