7 go
我需要为每个构建类型创建构建器(基础)和特定构建器.
e.g.
builder for html project
builder for node.js project
builder for python project
builder for java project
Run Code Online (Sandbox Code Playgroud)
....
主要功能如下:
文件:Builder.go
接口
type Builder interface {
Build(string) error
}
Run Code Online (Sandbox Code Playgroud)
文件: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)
}
Run Code Online (Sandbox Code Playgroud)
主要假设/过程:
mvn build npm install等)注意:旁边从build和path(应具体处理)的所有其它功能是相同的
像 zip copy
我应该在哪里放置
zip and copy(在结构中),例如我应该如何实现它们并将它们路由到构建器?我应该根据假设不同地构建项目吗?
SOLID的第一个原则是一段代码应该只承担一个职责。
考虑到上下文,任何人builder关心构建过程的一部分copy确实没有意义。zip这超出了builder他的责任范围。即使使用组合(嵌入)也不够简洁。
缩小范围,Builder顾名思义,其核心职责是构建代码。但更具体地说, 的Builder职责是在路径上构建代码。什么路径?最惯用的方式是当前路径,即工作目录。这向接口添加了两个辅助方法:Path() string返回当前路径和ChangePath(newPath string) error更改当前路径。实现很简单,保留单个字符串字段,因为当前路径主要完成这项工作。并且它可以很容易地扩展到一些远程进程。
如果我们仔细看的话,实际上有两个构建概念。一是整个构建过程,从创建临时目录到复制回来,总共五个步骤;另一个是构建命令,这是该过程的第三步。
这非常鼓舞人心。进程通常被表示为函数,就像经典的过程式编程所做的那样。所以我们写一个Build函数。它将所有 5 个步骤序列化,简单明了。
代码:
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.
Run Code Online (Sandbox Code Playgroud)
大多数内容都在评论中涵盖了,我真的很懒惰写所有这些copyDir/removeDir东西。设计部分没有提到的一件事是mkTempDir功能。如果代码在 中,Golang 会不高兴,因为/tmp/xxx/它在 之外GOPATH,而且更改起来会更麻烦,GOPATH因为它会破坏导入路径搜索,因此 golang 需要一个独特的函数来在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
}
Run Code Online (Sandbox Code Playgroud)
并将其与其他语言结合在一起:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
技巧之一是获取语言名称。GetLanguageName应该返回代码正在使用的语言的名称path。ioutil.ReadDir这可以通过使用检测文件名来完成。
另请注意,虽然我使Node结构非常简单并且仅存储一个path字段,但您可以轻松扩展它。就像Golang部分一样,您可以在那里添加构建选项。
编辑3:
关于包结构:
首先,我认为实际上所有的东西:Build函数、语言构建器和其他 util/helpers 都应该放入一个包中。他们都致力于同一个任务:构建一种语言。没有必要也几乎没有期望将任何代码片段隔离为另一个(子)包。
这意味着一个目录。剩下的确实是一些非常个人的风格,但我会分享我的:
我会将函数Build和接口Builder放入一个名为main.go. 如果前端代码很小并且非常可读,我也会将它们放入main.go,但如果它很长并且有一些 ui 逻辑,我会将其放入 afront-end.go或cli.go或ui.go,具体取决于实际代码。
接下来,对于每种语言,我将创建一个.go包含语言代码的文件。它清楚地表明我可以在哪里检查它们。或者,如果代码确实很小,将它们全部放在一个builders.go. 毕竟,现代编辑器完全有能力获得结构和类型的定义。
最后,所有copyDir,zipDir函数都转到util.go. 这很简单 - 它们是实用程序,大多数时候我们只是不想打扰它们。
| 归档时间: |
|
| 查看次数: |
787 次 |
| 最近记录: |