Ruby Gemspec 依赖:是否可以有一个 git 分支依赖?

94

是否可以在我的gemspec文件中设置git分支依赖关系?

我在考虑类似于以下的做法:

gem.add_runtime_dependency 'oauth2', :git => 'git@github.com:lgs/oauth2.git'

...但它不起作用。


我有同样的问题,只是我想要路径依赖性,而不是 Git 依赖性。难道没有办法绕过这个问题吗?也许可以在 gemspec 的某个地方加入一些 hackish Ruby 代码来解决? - Ajedi32
5个回答

48

这是不可能的,而且很可能永远不会实现,因为让 RubyGems 允许 gem 开发者要求用户安装特定版本的版本控制系统来访问 gem,这将过于强硬。gem 应该是自包含的,并具有最少的依赖项,以便人们可以在尽可能广泛的应用程序中使用它们。

如果你想要为自己的内部项目做到这一点,我的建议是使用 Bundler ,它支持这种方式非常好。


27
是的,但我该怎么做呢? - Luca G. Soave
33
如果你的宝石(gem)以后要包含在另一个宝石中(例如 foobar_gem),那怎么办呢?当 foobar_gem 要解决依赖关系时,它不会仅查找 gemspec 文件吗?请问需要怎样处理? - eremzeit
7
你有解决这个问题的方法吗?我遇到了完全相同的问题。 - msaspence
14
@eremzeit和@msaspence,由于你们得到了很多赞,我觉得有必要作出回应。这个问题没有解决方案,因为“你做错了”。如果使用Bundler依赖于Git仓库来构建一个单独的应用程序,那么是可以的,但是如果发布一个gem并依赖于GitHub或其他源代码仓库,那么完全是错误的。如果你要发布一个gem,所有它的依赖都必须作为gems一起发布。让一个正式的包(如gem)依赖于未经发布的源代码就好比本末倒置。请不要尝试这样做。 - gtd
31
创建一个gem和在rubygems上发布一个gem是两件不同的事情。一个私有但未公开的gem可能有它自己的私有依赖关系,这是可行的。RubyGems似乎没有为这种用例提供支持,但我并不认为这样做是错误的。只是没有太多的支持。我错了吗? - Stephen Crosby
显示剩余10条评论

15

编辑

根据评论者的说法,这已经不再正确。保留先前的信息供历史背景参考。

在Gemfile和.gemspec中复制对gem的引用现在似乎会在Bundler中引发警告消息,因此这个答案看起来已经不再正确。

过时信息

这篇由Yehuda Katz撰写的文章为我澄清了类似的困惑。它说,在仅用于开发的情况下,最好将git相关内容添加到gemfile中,但是bundler仍将使用gemspec中的依赖/版本信息(对我来说似乎有点神奇,但我相信Yehuda)。


4
那有什么神奇的呢?Bundler只会从Gemfile中读取 - 但如果您在其中放置了 gemspec,它也会从gemspec中读取。因此,当您运行 bundle install 时,我认为(但未经测试)发生的是Bundler安装Gemfile中指定的gem。由于Bundler已经安装了它,该gem可供需要它的gem进行 require,而不管它是否来自gem存储库。没有魔法,只是Bundler像往常一样工作。 - Marnen Laibow-Koser
2
在Gemfile和.gemspec文件中复制对gem的引用现在似乎会在Bundler中引发警告信息,因此这个答案似乎不再正确了... - Andy Jones

7

我也在尝试解决这个问题。我想到了以下的解决方案(不确定你是否发布了你的gem或者拥有重新分发该oauth2 gem的权利)。

在需要oauth2 gem的gem中运行以下命令。

git submodule add git@github.com:lgs/oauth2.git lib/oauth2

如果您需要不同于默认的分支
cd lib/oauth2 && git checkout <branchname_or_ref>
cd .. && git add lib/oauth2
git commit -m "adding outh2 submodule"

在您的 gemspec 中,在 require 版本行上方添加以下内容。
$:.push File.expand_path('../lib/oauth2/lib', __FILE__)

同时,您需要将所有oauth2 gem的运行时依赖项添加到您的gemspec中。 我还没有找到解决方法。

这是我所做的事情,它对我们起作用,因为我们的gem是通过git要求的,所以我不确定这是否适用于发布在rubygems上的gem。


如果你编写了两个 gem 并且两者都在积极开发中,将依赖项作为子模块添加是正确的解决方案。 - Benjineer
重要的是,如果您这样做,可能需要在主机应用程序中使用以下代码:gem 'my_gem', git: 'git@github.com:me/myrepo', submodules: true如果您从Github安装。 - Joe Edgar

2
我找到了一个相当简单的解决方法:
假设你在项目 P 中想要使用自己制作的 gem tools,而这个 gem 本身使用了一个操作系统的 gem oauth2
如果你在 oauth2 中进行了修补,并且需要在你的 gem tools 中使用这个修补程序,根据被接受的答案,你将无法在 gem 中解决这个问题。
然而,你可以在项目 P 的 Gemfile 中指定你想要的版本,这个版本将在运行时由 tools 使用:
gem 'oauth2', github: 'lgs/oauth2'

这是我的一个真实例子。

1

我曾经遇到类似的问题,这是我发现的解决方法。你不能直接为其他gem添加git分支,但是你可以用另一种方式实现。你可以在自定义gem的gemfile中定义一个带有仓库链接和分支名称的私有gem。

gem 'gem_name', '>=0.1.1', git: 'repository_link ', branch: 'brnach_name'

并运行bundle install

现在您可以在gemspec文件中提及它,无需添加版本,因为它已经从Gemfile.lock中选择了。

spec.add_runtime_dependency 'sms_service'

注意: 确保在Gemfile中将gemspec放在底部。这样,它将首先安装必要的gems,然后将它们作为依赖项添加到您的gem中。

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'sms_service', '>=0.1.1', git: 'repository link', branch: 'branch_name'

gemspec

它对我没用 :( - kimerseen
这可以在本地运行,但对于通过rubygems.org安装它的任何人来说,它可能不知道如何获取分支。 - lulalala
添加 'gemspec' 可以通过运行 Gemfile 然后 gemspec 来帮助解决问题。但是第二次定义 gem,即 spec.add_runtime..(如上所述),只会导致错误的 gem 版本加载。要点是,在 Gemfile 中引用需要的分支,并确保将 gemspec 添加到 Gemfile 底部。 - Evolve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接