我需要为每种构建类型创建构建器(基础)和特定的构建器。
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
我应该将放置在
zip and copy
(结构中)的哪个位置,例如,应该如何实现它们并将它们传递给构建器?我是否应该根据假设对项目进行结构设计?
SOLID 的第一条原则说一段代码应该只承担一个责任。
发生在该背景下,它确实是没有意义的,任何builder
关心copy
和zip
构建过程的一部分。这超出了builder
责任。即使使用合成(嵌入)也不够整洁。
Builder
顾名思义,缩小范围,其核心职责是构建代码。但更具体地说,Builder
的责任是在路径上构建代码。什么路 最惯用的方法是
当前路径 , 工作目录 。这会在接口中添加两个方法:Path() string
返回 当前路径
和ChangePath(newPath string) error
更改 当前路径
。该方法很简单,保留一个字符串字段,因为当前路径通常可以完成此工作。而且它可以轻松地扩展到某些远程过程。
如果我们仔细地看一下,这无疑是两个 构建 概念。一个是整个构建 过程 ,从制作temp目录到将其复制回去,全部五个步骤。另一个是build
命令 ,这是该过程的第三步。
那是非常鼓舞人心的。就像传统的程序编程一样,过程是作为功能呈现的过程。因此,我们编写了一个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.
大部分的东西都涵盖在评论,我真的很砍伐懒得所有写那些copyDir
/
removeDir
东西。在设计部分中没有提到的一件事是mkTempDir
功能。如果代码位于/tmp/xxx/
之外GOPATH
,那么Golang会感到不满意,并且由于更改代码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
}
并将其与其他语言结合在一起:
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
检测文件名来完成。
还要注意,尽管我使Node
结构非常简单,只存储一个path
字段,但是您可以轻松扩展它。就像Golang
部分一样,您可以在此处添加构建选项。
编辑3:
关于包装结构:
首先,我实际上认为所有内容:Build
函数,语言构建器和其他util /
helpers应该放在一个包中。它们都是为一项任务而工作:建立一种语言。没有必要,几乎没有期望将任何代码段隔离为另一个(子)程序包。
因此,这意味着一个目录。剩下的确实是一些非常个人化的风格,但我会分享我的:
我会将函数Build
和接口Builder
放入一个名为的文件中main.go
。如果前端代码极少且可读性强,我也会将它们放入其中main.go
,但是如果前端代码很长且具有某些ui逻辑,则根据实际代码将其放入front- end.go
or cli.go
或ui.go
or中。
接下来,对于每种语言,我将.go
使用语言代码创建一个文件。这清楚表明我可以在哪里检查它们。或者,如果代码真的很小,那么将它们全部组合到一个中也不是坏主意builders.go
。毕竟,现代编辑器不仅仅具有定义结构和类型的能力。
最后,所有的copyDir
,zipDir
功能都到了util.go
。这很简单-它们是实用程序,大多数时候我们只是不想打扰它们。
我面临一个生成器类继承的序列化问题。如下所示: 基类: 我看到以下例外: 有人知道如何避免这个问题吗?
问题内容: 有没有一种方法可以在Windows下针对Go v1.7生成dll? 我尝试了经典 但是得到 Windows / amd64不支持-buildmode = shared 更新 好的,我知道了。对于那些感兴趣的人:https : //groups.google.com/forum/#!topic/golang- dev/ckFZAZbnjzU 问题答案: 从Go 1.10开始,Window
由于无法解析最后一个链接调用,未定义方法,因此此调用将不会编译。所以这种方式要求所有调用都以特定的顺序链接起来,这是非常不切实际的,特别是对于一个深度层次结构树。 现在,在我寻找答案的过程中,我遇到了一个Java Builder类的子类,它建议使用奇怪的递归泛型模式。但是,由于我的层次结构不包含一个抽象类,所以这个解决方案对我不起作用。但是这种方法依赖于抽象和多态性来发挥作用,这就是为什么我不相信
问题内容: 我正在尝试使用我的go应用程序创建一个docker映像。该应用程序(在MacOS上开发)取决于哪个,而又取决于我在Docker映像中安装的对象,如下所示: 我收到以下错误: 我/app/folder/vendor/github.com/confluentinc/confluent-kafka-go/kafka ../folder/vendor/github.com/confluenti
我在开发一个Android应用程序。我需要为我的应用程序构建一个URI来发出API请求。除非有其他方法将变量放入URI中,否则这是我找到的最简单的方法。我发现您需要使用,但我不太确定如何使用。我的url是: 我的代码如下: 我知道我可以执行,但是如何将它集成到中呢?我应该添加、等内容吗?或者这不是做这件事的方法?另外,还有其他更简单的方法可以将变量添加到URI/URL中吗?
我正在尝试在docker文件上构建我的go应用程序。在我的内心深处。mod有一个需要身份验证/ssh的私有包。这个问题类似于在Docker中使用私有模块构建Go应用程序,但在我的情况下,我必须从而不是中提取包。这是我的dockerfile: 我试图按照这个教程https://divan.dev/posts/go_get_private/,通过更改到仍然失败。 以下是错误详细信息: 这里有人知道如何