【问题标题】:Google Go AppEngine imports and conflicts when serving / testing服务/测试时 Google Go AppEngine 导入和冲突
【发布时间】:2015-01-03 19:55:55
【问题描述】:

所以我花了两天的大部分时间试图弄清楚这一点,但无论我做什么,我都无法把事情理顺。这是发生了什么:

  • 使用 Go 和 Appengine。我在尝试时遇到问题 让适当的单元测试正常工作。
  • 我尝试了很多结构,但这里是我现在所处位置的示例:https://github.com/markhayden/SampleIssue
  • 我在goapp servegoapp test -v ./src/lib1 中遇到依赖问题,这取决于我设置导入路径的方式。

如果我使用"src/lib1" 作为我的导入路径,然后使用goapp serve。我的应用程序启动并运行良好,但是当我运行测试时出现以下故障:

src/lib1/lib1.go:5:2: cannot find package "src/lib2" in any of:
    /Users/USERNAME/go_appengine/goroot/src/pkg/src/lib2 (from $GOROOT)
    /Users/markhayden/Projects/go/src/src/lib2 (from $GOPATH)

同样,如果我使用 "dummy/src/lib1" 作为我的路径,我的测试会很开心并且运行良好,但是在 goapp serve 使用我现在得到的应用程序时:

2014/11/06 20:33:34 go-app-builder: Failed parsing input: app file lib1.go conflicts with same file imported from GOPATH

已经摆弄了各种不同的选项,无法弄清楚如何处理依赖关系,但仍然有可靠的测试。也许它是一个 appengine / golang 错误?还是我错过了什么?

任何帮助将不胜感激。提前致谢!


根据第一条评论反馈更新了所有内容。我可以运行测试(就像我以前能够做的那样),但我仍然无法为应用程序提供服务。这是我在运行goapp serve 时得到的结果

INFO     2014-11-07 17:24:48,727 devappserver2.py:745] Skipping SDK update check.
INFO     2014-11-07 17:24:48,748 api_server.py:172] Starting API server at: http://localhost:60732
INFO     2014-11-07 17:24:48,751 dispatcher.py:185] Starting module "default" running at: http://localhost:8080
INFO     2014-11-07 17:24:48,754 admin_server.py:118] Starting admin server at: http://localhost:8000
ERROR    2014-11-07 17:24:49,041 go_runtime.py:171] Failed to build Go application: (Executed command: /Users/markhayden/go_appengine/goroot/bin/go-app-builder -app_base /Users/markhayden/Projects/go/src/github.com/markhayden/SampleIssue -arch 6 -dynamic -goroot /Users/markhayden/go_appengine/goroot -nobuild_files ^^$ -unsafe -gopath /Users/markhayden/Projects/go -print_extras_hash lib1/lib1.go lib2/lib2_test.go main_test.go main.go lib1/lib1_test.go lib2/lib2.go)

2014/11/07 09:24:49 go-app-builder: Failed parsing input: app file lib2.go conflicts with same file imported from GOPATH

$GOPATH = /Users/markhayden/Projects/go $GOROOT = 未设置(根据文档,如果您不使用自定义目录,则不需要设置)

应用结构:

$GOPATH/src/github.com/markhayden/SampleIssue/
 - app.yaml
 - /lib1
    - lib1_test.go
    - lib1.go
 - /lib2
    - lib2_test.go
    - lib2.go
 - main_test.go
 - main.go

在 main.go 中:

import (
    "fmt"
    "github.com/markhayden/SampleIssue/lib1"
    "net/http"
)

在 lib1/lib1.go 中:

import (
    "fmt"
    "github.com/markhayden/SampleIssue/lib2"
)

【问题讨论】:

    标签: google-app-engine go


    【解决方案1】:

    我在遵循各种答案和理解如何解决问题时遇到了很多麻烦。

    但经过大量研究,我相信我了解原因和解决方案:

    Google 应用程序构建器工具会进行一些路径修改并导致此问题。 他们知道这个错误,但没有 ETA 来修复它。

    问题总结: 内部或以下的任何 .go 文件都将被双重导入包含 main.go / app.yaml 的目录...

    总而言之,只要确保我们所有的文件/包都是兄弟姐妹,而不是保存这两个文件的目录的后代...

    【讨论】:

    • 我在同一个代码仓库中提供服务,并没有注意到我的文件夹之间存在细微的结构差异——这确实是我的问题。谢谢杜威。作为旁注 - 这似乎只在项目是自引用的情况下才重要,即您在同一个项目中的包之间链接。
    【解决方案2】:

    Appengine“与从 GOPATH 导入的相同文件冲突”问题:

    Appengine 正在根目录下导入内容(即 app.yaml 所在的位置)。这将导致两次导入,一次在扫描目录时由 appengine 进行,另一次在显式导入时由您的源进行。

    你有两个选择:

    不要对 appengine 使用完整的导入路径(用于子文件夹包)。

    • 删除导入的源存储库部分。所以而不是 “github.com/blah/blah”应该是“blah/blah”。

      注意:这有点糟糕,因为它使您的构建和软件应用引擎变得特定。您可以通过使用build constraints 使这变得更好——也许——。例如+build !appengine+build !appengine 包含/删除构建中的某些文件,具体取决于您是否针对 appengine。

    将您的模块/依赖项(子文件夹)移动到单独的独立项目中,以使其符合完整路径导入约定:

    1. 摆脱主项目中的所有目录/依赖项(其中 您的 app.yaml 是),因此 appengine 无法扫描并找到它们。
    2. 将它们移到另一个独立项目(我做了 SampleIssueDeps) 没有 不是 子目录的 app.yaml(例如 /MarkHayden/SampleIssueDeps)。
    3. 然后通过 全路径导入。例如github.com/MarkHayden/SampleIssueDeps/lib1。

    总结:对于 appengine 项目中的子文件夹包,不要包含导入路径的“源存储库”部分,或者仅使用 appengine 到 init() 并移动所有其他代码分离项目并使用外部依赖项。

    【讨论】:

    • 首先,非常感谢您抽出宝贵的时间查看。其次,我已经阅读了几次“如何编写 Go 代码”,并在 appengine 之外组织了几个项目,没有任何问题。这个组织有点不稳定,因为我一直在尝试解决问题并四处移动。无论如何,我开始重新尝试您的上述方法,但仍然遇到问题。由于篇幅原因,将我看到的内容添加到原始帖子中。
    • 为了让它与你的目录结构一起工作(我仍然会修复它更传统),你可以让你的导入匹配你的 GOPATH 之后的任何内容。例如导入“SampleIssue/app/src/lib1”。如果我在本地将您的应用程序拉入 $GOPATH/github.com/markhayden/ 并将您的导入语句修复为我的 $GOPATH 之后的所有内容,例如“github.com/markhayden/SampleIssue/app/src/lib1”然后一切正常。请注意我必须如何包含 /app/src/ 目录。也就是说,我会杀死 app 和 src 目录并将 src 中的所有内容移动到 SampleIssue 文件夹中,这样你的导入就会简单得多。
    • 是的,我根据您的建议更改了结构(在上面添加了更新)。所以现在我的 gopath 是/Users/markhayden/Projects/go,我的目录结构如下所示:f.cl.ly/items/1r2N46432K1z0j0w0T0N/dirstruct.jpg
    • 好的,在您的新组织中,我重现了“与从 GOPATH 导入的同一文件发生冲突”的问题。看来 appengine 正在根目录(app.yaml 文件所在的位置)下手动扫描导入,并且这些与您显式导入的路径冲突。添加到上面的答案...
    • 现在可以使用了。最终将所有内容放在一个主文件夹中,然后推荐结构,以便它可以全部存在于一个存储库中,但一切似乎都在工作。将不得不返工一些事情,但真的不能感谢你。
    【解决方案3】:

    我想出了另一个在这里没有讨论的选项,在我看来更容易处理(并且让您的应用不那么特定于 appengine)。假设您有位于github.com/blah/blah 的 repo,现在 repo 的根文件夹定义了您的应用引擎服务器。

    首先,将app.yaml 和其他应用引擎特定文件(不是.go 文件)移动到github.com/blah/blah/appengine/app.yaml

    接下来,无论您在何处运行应用引擎的 init 函数,都将其重命名为 func Run() { ... },然后在 github.com/blah/blah/whatever.go 中编写如下内容:

    package appengine
    
    import "github.com/blah/blah"
    
    func init() {
        blah.Run()
    }
    

    根据我的经验,这已经解决了问题并使事情变得更加容易。如果我遇到任何使其成为糟糕解决方案的重大问题,我会更新此内容。

    【讨论】:

    • 感谢您的回答。绝对是一个更清洁的解决方案(并避免命名空间不兼容)。
    • 完美运行。我尝试了接受的答案,但即使它已编译,也无法让 atom 同意该解决方案。但是,此解决方案可以编译,并与 atom(go-plus) 一致。
    • 我发现记录在案的解决方案 here 更适合这种情况。注意nobuild_files:...app.yaml配置。
    • @iswak 在我的辩护中,您链接到的线程是在我回答后 10 个月创建的,就像这条评论被超级延迟了 ;)
    猜你喜欢
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多