Commit 50f344b7 authored by Natanael Copa's avatar Natanael Copa

main/abuild: upgrade to 2.22.0

parent a655bcb0
From a6641817147c5fd379245cc080af8bec77315890 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Thu, 9 Apr 2015 08:47:56 +0300
Subject: [PATCH] abuild: preserve all xattrs
by default getfattr omits system xattrs like security.capability
---
abuild.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/abuild.in b/abuild.in
index 3e7ffaf..3ed5417 100644
--- a/abuild.in
+++ b/abuild.in
@@ -1679,7 +1679,7 @@ stripbin() {
scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
| sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
| while read filename; do
- XATTR=$(getfattr -d "${filename}")
+ XATTR=$(getfattr --match="*" --dump "${filename}")
${CROSS_COMPILE}strip "${filename}"
[ -n "$XATTR" ] && (echo "$XATTR" | setfattr --restore=-)
done
--
2.3.5
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=abuild
pkgver=2.21.0_git20150408
pkgver=2.22.0
_ver=${pkgver%_git*}
pkgrel=1
pkgrel=0
pkgdesc="Script to build Alpine Packages"
url="http://git.alpinelinux.org/cgit/abuild/"
arch="all"
......@@ -20,8 +20,6 @@ subpackages="apkbuild-cpan:cpan"
options="suid"
pkggroups="abuild"
source="http://dev.alpinelinux.org/archive/abuild/abuild-$_ver.tar.xz
git.patch
0001-abuild-preserve-all-xattrs.patch
"
_builddir="$srcdir/$pkgname-$_ver"
......@@ -60,12 +58,6 @@ cpan() {
mv "$pkgdir"/usr/bin/apkbuild-cpan "$subpkgdir"/usr/bin/
}
md5sums="126cbde6e4fdf537571a03a97d01d348 abuild-2.21.0.tar.xz
453ee698af510fc0cf10a33020e37e73 git.patch
79ad3d35bab42098add7fa8bcb7d759b 0001-abuild-preserve-all-xattrs.patch"
sha256sums="08689cbf8818c81d9e52e3397529adcb0e279a21d33dfe4f0678d0ef778767f3 abuild-2.21.0.tar.xz
7e7f9a837c2c6a2bddb2db80f86b2cad212cbb0cc8f2a8b63534dd5a3bc52318 git.patch
4b7102a82a4f12ee3344c027352868a0bc1d9c1af4ac8f66c11a2986cd4d6d11 0001-abuild-preserve-all-xattrs.patch"
sha512sums="b304dbb82563ec8ae23376c17ee27b3d49e9c1b74bd14b7a912ca88239ed3c7b2fabeb6209a6d4485c6dbab8491abb8b42f801f5fd9310691da60e630061646b abuild-2.21.0.tar.xz
6ab114cd383d29244124e5cf440ef17f292e01a683d21c153f808d7757e38e1b575384d5d4b2a3314c17a5656c64361703c3f746577266ae4403edcf353cc5e8 git.patch
c995d2874d9a54c68efa51a8b7e7185748f2369b62011f3998d906aa8118c0944594a258062cb46bfb75b89d78cae13b59cf84de2cf6630f4d2bdb8c0282972b 0001-abuild-preserve-all-xattrs.patch"
md5sums="46184ce2dc86294f3f8de9fe80200a7e abuild-2.22.0.tar.xz"
sha256sums="0d24dca8fa8acc6a033e73d6cfbc6062e91c14e7b73456bd9a273f570cd91e47 abuild-2.22.0.tar.xz"
sha512sums="c95b8ecba39ba9a76f2de6fc33aae70e040d6d6041b2365066ce2a8cb92a8ae115697f93add1c8e0ae71b1cac1ed43437416dd323fed8959a0610cc204b4a0f1 abuild-2.22.0.tar.xz"
diff --git a/Makefile b/Makefile
index ccfed0d..7053e2d 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,8 @@ datadir ?= $(prefix)/share/$(PACKAGE)
abuildrepo ?= ~/.cache/abuild
SCRIPTS := abuild buildrepo abuild-keygen abuild-sign newapkbuild \
- abump apkgrel buildlab apkbuild-cpan checkapk
+ abump apkgrel buildlab apkbuild-cpan checkapk \
+ apkbuild-gem-resolver
USR_BIN_FILES := $(SCRIPTS) abuild-tar abuild-sudo
SAMPLES := sample.APKBUILD sample.initd sample.confd \
sample.pre-install sample.post-install
diff --git a/abuild-tar.c b/abuild-tar.c
index 4a88882..2f29d30 100644
--- a/abuild-tar.c
+++ b/abuild-tar.c
@@ -1,6 +1,6 @@
/* abuild-tar.c - A TAR mangling utility for .APK packages
*
- * Copyright (C) 2009 Timo Teräs <timo.teras@iki.fi>
+ * Copyright (C) 2009-2014 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -89,6 +89,19 @@ static void put_octal(char *s, size_t l, size_t value)
*(ptr--) = '0';
}
+static void tarhdr_checksum(struct tar_header *hdr)
+{
+ const unsigned char *src;
+ size_t chksum, i;
+
+ /* Recalculate checksum */
+ memset(hdr->chksum, ' ', sizeof(hdr->chksum));
+ src = (const unsigned char *) hdr;
+ for (i = chksum = 0; i < sizeof(*hdr); i++)
+ chksum += src[i];
+ put_octal(hdr->chksum, sizeof(hdr->chksum)-1, chksum);
+}
+
static int usage(void)
{
fprintf(stderr,
@@ -120,7 +133,7 @@ static ssize_t full_read(int fd, void *buf, size_t count)
} while (1);
if (total == 0 && n < 0)
- return -1;
+ return -errno;
return total;
}
@@ -142,7 +155,7 @@ static ssize_t full_write(int fd, const void *buf, size_t count)
} while (1);
if (total == 0 && n < 0)
- return -1;
+ return -errno;
return total;
}
@@ -163,82 +176,182 @@ static ssize_t full_splice(int from_fd, int to_fd, size_t count)
} while (1);
if (total == 0 && n < 0)
- return -1;
+ return -errno;
return total;
}
-static int do_it(const EVP_MD *md, int cut)
+#define BUF_INITIALIZER {0}
+struct buf {
+ char *ptr;
+ size_t size;
+ size_t alloc;
+};
+
+static void buf_free(struct buf *b)
+{
+ free(b->ptr);
+}
+
+static int buf_resize(struct buf *b, size_t newsize)
{
- struct tar_header hdr;
- size_t size, aligned_size;
void *ptr;
- int dohash = 0, r;
+
+ if (b->alloc >= newsize) return 0;
+ ptr = realloc(b->ptr, newsize);
+ if (!ptr) return -ENOMEM;
+ b->ptr = ptr;
+ b->alloc = newsize;
+ return 0;
+}
+
+static int buf_padto(struct buf *b, size_t alignment)
+{
+ size_t oldsize, newsize;
+ oldsize = b->size;
+ newsize = (oldsize + alignment - 1) & -alignment;
+ if (buf_resize(b, newsize)) return -ENOMEM;
+ b->size = newsize;
+ memset(b->ptr + oldsize, 0, newsize - oldsize);
+ return 0;
+}
+
+static int buf_read_fd(struct buf *b, int fd, size_t size)
+{
+ ssize_t r;
+
+ r = buf_resize(b, size);
+ if (r) return r;
+
+ r = full_read(fd, b->ptr, size);
+ if (r == size) {
+ b->size = r;
+ return 0;
+ }
+ b->size = 0;
+ if (r < 0) return r;
+ return -EIO;
+}
+
+static int buf_write_fd(struct buf *b, int fd)
+{
+ ssize_t r;
+ r = full_write(fd, b->ptr, b->size);
+ if (r == b->size) return 0;
+ if (r < 0) return r;
+ return -ENOSPC;
+}
+
+static int buf_add_ext_header_hexdump(struct buf *b, const char *hdr, const char *value, int valuelen)
+{
+ size_t oldsize = b->size;
+ int i, len;
+
+ /* "%u %s=%s\n" */
+ len = 1 + 1 + strlen(hdr) + 1 + valuelen*2 + 1;
+ for (i = len; i > 9; i /= 10) len++;
+
+ if (buf_resize(b, b->size + len)) return -ENOMEM;
+ b->size += snprintf(&b->ptr[b->size], len, "%u %s=", len, hdr);
+ for (i = 0; i < valuelen; i++)
+ b->size += snprintf(&b->ptr[b->size], 3, "%02x", (int)(unsigned char)value[i]);
+ b->ptr[b->size++] = '\n';
+
+ return 0;
+}
+
+static void add_legacy_checksum(struct tar_header *hdr, const EVP_MD *md, const char *digest)
+{
struct {
char id[4];
uint16_t nid;
uint16_t size;
} mdinfo;
- if (md != NULL) {
- memcpy(mdinfo.id, "APK2", 4);
- mdinfo.nid = EVP_MD_nid(md);
- mdinfo.size = EVP_MD_size(md);
- }
+ memcpy(mdinfo.id, "APK2", 4);
+ mdinfo.nid = EVP_MD_nid(md);
+ mdinfo.size = EVP_MD_size(md);
+ memcpy(&hdr->linkname[3], &mdinfo, sizeof(mdinfo));
+ memcpy(&hdr->linkname[3+sizeof(mdinfo)], digest, mdinfo.size);
+ tarhdr_checksum(hdr);
+}
+
+static int do_it(const EVP_MD *md, int cut)
+{
+ char checksumhdr[32], digest[EVP_MAX_MD_SIZE];
+ struct buf data = BUF_INITIALIZER, pax = BUF_INITIALIZER;
+ struct tar_header hdr, paxhdr;
+ size_t size, aligned_size;
+ int dohash = 0, r, ret = 1;
+
+ if (md) snprintf(checksumhdr, sizeof(checksumhdr), "APK-TOOLS.checksum.%s", EVP_MD_name(md));
do {
if (full_read(STDIN_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
- return 0;
+ goto err;
if (cut && hdr.name[0] == 0)
- return 0;
+ break;
size = GET_OCTAL(hdr.size);
aligned_size = (size + 511) & ~511;
- if (md != NULL)
- dohash = (hdr.typeflag == '0' || hdr.typeflag == '7');
+ if (hdr.typeflag == 'x') {
+ memcpy(&paxhdr, &hdr, sizeof(hdr));
+ if (buf_read_fd(&pax, STDIN_FILENO, aligned_size)) goto err;
+ pax.size = size;
+ continue;
+ }
+
+ dohash = md && (hdr.typeflag == '0' || hdr.typeflag == '7' || hdr.typeflag == '2');
if (dohash) {
- const unsigned char *src;
- int chksum, i;
-
- ptr = malloc(aligned_size);
- if (full_read(STDIN_FILENO, ptr, aligned_size) != aligned_size)
- return 1;
-
- memcpy(&hdr.linkname[3], &mdinfo, sizeof(mdinfo));
- EVP_Digest(ptr, size, &hdr.linkname[3+sizeof(mdinfo)],
- NULL, md, NULL);
-
- /* Recalculate checksum */
- memset(hdr.chksum, ' ', sizeof(hdr.chksum));
- src = (const unsigned char *) &hdr;
- for (i = chksum = 0; i < sizeof(hdr); i++)
- chksum += src[i];
- put_octal(hdr.chksum, sizeof(hdr.chksum)-1, chksum);
+ if (buf_read_fd(&data, STDIN_FILENO, aligned_size)) goto err;
+
+ if (hdr.typeflag != '2') {
+ EVP_Digest(data.ptr, size, digest, NULL, md, NULL);
+ add_legacy_checksum(&hdr, md, digest);
+ } else {
+ EVP_Digest(hdr.linkname, strlen(hdr.linkname), digest, NULL, md, NULL);
+ }
+
+ buf_add_ext_header_hexdump(&pax, checksumhdr, digest, EVP_MD_size(md));
+ PUT_OCTAL(paxhdr.size, pax.size);
+ tarhdr_checksum(&paxhdr);
+ }
+
+ if (pax.size) {
+ /* write pax header + content */
+ if (full_write(STDOUT_FILENO, &paxhdr, sizeof(paxhdr)) != sizeof(paxhdr) ||
+ buf_padto(&pax, 512) ||
+ buf_write_fd(&pax, STDOUT_FILENO)) goto err;
}
- if (full_write(STDOUT_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
- return 2;
+ if (full_write(STDOUT_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr)) goto err;
if (dohash) {
- if (full_write(STDOUT_FILENO, ptr, aligned_size) != aligned_size)
- return 2;
- free(ptr);
+ if (buf_write_fd(&data, STDOUT_FILENO)) goto err;
} else if (aligned_size != 0) {
r = full_splice(STDIN_FILENO, STDOUT_FILENO, aligned_size);
if (r == -1) {
while (aligned_size > 0) {
if (full_read(STDIN_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
- return 1;
+ goto err;
if (full_write(STDOUT_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr))
- return 2;
+ goto err;
aligned_size -= sizeof(hdr);
}
- } else if (r != aligned_size)
- return 2;
+ } else if (r != aligned_size) goto err;
}
+
+ memset(&paxhdr, 0, sizeof(paxhdr));
+ pax.size = 0;
} while (1);
+
+ ret = 0;
+err:
+ buf_free(&data);
+ buf_free(&pax);
+ return ret;
}
int main(int argc, char **argv)
diff --git a/abuild.in b/abuild.in
index 5459a9b..93c723d 100644
--- a/abuild.in
+++ b/abuild.in
@@ -616,13 +616,12 @@ postcheck() {
return 1
fi
fi
- # look for *.la files
- i=$(find "$dir" -name '*.la' | sed "s|^$dir|\t|")
- if [ -n "$i" ] && ! options_has "libtool"; then
- error "Libtool archives (*.la) files found and \$options has no 'libtool' flag:"
- echo "$i"
- return 1
+
+ # remove *.la files if libtool is not set
+ if ! options_has "libtool"; then
+ find "$dir" -name '*.la' -type f -delete
fi
+
# look for /usr/lib/charset.alias
if [ -e "$dir"/usr/lib/charset.alias ] \
&& ! options_has "charset.alias"; then
@@ -816,18 +815,13 @@ EOF
echo "replaces_priority = $replaces_priority" >> "$pkginfo"
fi
- for i in $license; do
- echo "license = $i" >> "$pkginfo"
- done
+ echo "license = $license" >> "$pkginfo"
for i in $replaces; do
echo "replaces = $i" >> "$pkginfo"
done
for i in $deps; do
echo "depend = $i" >> "$pkginfo"
done
- for i in $conflicts; do
- echo "conflict = $i" >> "$pkginfo"
- done
for i in $provides; do
echo "provides = $i" >> "$pkginfo"
done
@@ -1140,7 +1134,7 @@ create_apks() {
touch .dummy
set -- .dummy
fi
- tar -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
+ tar --xattrs -c "$@" | abuild-tar --hash | gzip -9 >"$dir"/data.tar.gz
msg "Create checksum..."
# append the hash for data.tar.gz
@@ -1298,6 +1292,8 @@ default_dev() {
done
cd "$pkgdir" || return 0
+ local libdirs=usr/
+ [ -d lib/ ] && libdirs="lib/ $libdirs"
for i in usr/include usr/lib/pkgconfig usr/share/aclocal\
usr/share/gettext usr/bin/*-config \
usr/share/vala/vapi usr/share/gir-[0-9]*\
@@ -1305,7 +1301,7 @@ default_dev() {
usr/lib/qt*/mkspecs \
usr/lib/cmake \
$(find . -name include -type d) \
- $(find lib/ usr/ -name '*.[acho]' \
+ $(find $libdirs -name '*.[acho]' \
-o -name '*.prl' 2>/dev/null); do
if [ -e "$pkgdir/$i" ] || [ -L "$pkgdir/$i" ]; then
d="$subpkgdir/${i%/*}" # dirname $i
@@ -1532,7 +1528,7 @@ deptrace() {
# build and install dependencies
builddeps() {
- local pkg= i= missing= conflicts=
+ local pkg= i= missing=
local hostdeps= builddeps= installed_hostdeps= installed_builddeps=
[ -n "$nodeps" ] && return 0
msg "Analyzing dependencies..."
@@ -1562,27 +1558,20 @@ builddeps() {
# find which deps are missing
for i in $builddeps; do
- if [ "${i#\!}" != "$i" ]; then
- $APK info --quiet --installed "${i#\!}" \
- && conflicts="$conflicts ${i#\!}"
+ if [ "${i#\!}" != "$i" ] && $APK info --quiet --installed "${i#\!}"; then
+ error "Conflicting package installed: ${i#\!}"
elif ! deplist_has $i $installed_builddeps || [ -n "$upgrade" ]; then
missing="$missing $i"
fi
done
for i in $hostdeps; do
- if [ "${i#\!}" != "$i" ]; then
- $APK info --quiet --installed --root "$CBUILDROOT" "${i#\!}" \
- && conflicts="$conflicts ${i#\!}"
+ if [ "${i#\!}" != "$i" ] && $APK info --quiet --installed --root "$CBUILDROOT" "${i#\!}"; then
+ error "Conflicting package installed: ${i#\!}"
elif ! deplist_has $i $installed_hostdeps || [ -n "$upgrade" ]; then
missing="$missing $i"
fi
done
- if [ -n "$conflicts" ]; then
- error "Conflicting package(s) installed:$conflicts"
- return 1
- fi
-
if [ -z "$install_deps" ] && [ -z "$recursive" ]; then
# if we dont have any missing deps we are done now
[ -z "$missing" ] && return 0
@@ -1687,7 +1676,11 @@ stripbin() {
msg "Stripping binaries"
scanelf --recursive --nobanner --etype "ET_DYN,ET_EXEC" . \
| sed -e 's:^ET_DYN ::' -e 's:^ET_EXEC ::' \
- | xargs -r ${CROSS_COMPILE}strip
+ | while read filename; do
+ XATTR=$(getfattr -d "${filename}")
+ ${CROSS_COMPILE}strip "${filename}"
+ [ -n "$XATTR" ] && (echo "$XATTR" | setfattr --restore=-)
+ done
}
# simply list target apks
@@ -2004,6 +1997,7 @@ fi
# if we want build debug package
if [ -n "$DEBUG" ] || subpackage_types_has "dbg"; then
CFLAGS="$CFLAGS -g"
+ CXXFLAGS="$CXXFLAGS -g"
options="$options !strip"
fi
diff --git a/apkbuild-gem-resolver.in b/apkbuild-gem-resolver.in
new file mode 100644
index 0000000..b93525e
--- /dev/null
+++ b/apkbuild-gem-resolver.in
@@ -0,0 +1,302 @@
+#!/usr/bin/ruby
+
+# APKBUILD dependency resolver for RubyGems
+# Copyright (C) 2014 Kaarle Ritvanen
+
+require 'augeas'
+require 'optparse'
+require 'rubygems/dependency'
+require 'rubygems/resolver'
+require 'rubygems/spec_fetcher'
+
+class Aport
+ RUBY_SUBPACKAGES = {
+ '2.0.0_p353' => {
+ 'ruby-minitest' => ['minitest', '4.3.2'],
+ 'ruby-rake' => ['rake', '0.9.6'],
+ 'ruby-rdoc' => ['rdoc', '4.0.0', 'ruby-json']
+ },
+ '2.0.0_p481' => {
+ 'ruby-minitest' => ['minitest', '4.3.2'],
+ 'ruby-rake' => ['rake', '0.9.6'],
+ 'ruby-rdoc' => ['rdoc', '4.0.0', 'ruby-json']
+ },
+ '2.1.5' => {
+ 'ruby-json' => ['json', '1.8.1'],
+ 'ruby-minitest' => ['minitest', '4.7.5'],
+ 'ruby-rake' => ['rake', '10.1.0'],
+ 'ruby-rdoc' => ['rdoc', '4.1.0', 'ruby-json']
+ },
+ '2.2.1' => {
+ 'ruby-json' => ['json', '1.8.1'],
+ 'ruby-minitest' => ['minitest', '5.4.3'],
+ 'ruby-rake' => ['rake', '10.4.2'],
+ 'ruby-rdoc' => ['rdoc', '4.2.0', 'ruby-json'],
+ 'ruby-io-console' => [ 'io-console', '0.4.2'] # its actually 0.4.3 but
+ # that version is not
+ # published on network
+ }
+ }
+
+ @@aports = {}
+ @@subpackages = []
+
+ def self.initialize testing
+ Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD) do |aug|
+ dir = Dir.pwd
+ aug.transform(:lens => 'Shellvars.lns', :incl => dir + '/*/ruby*/APKBUILD')
+ aug.load
+
+ apath = '/files' + dir
+ fail if aug.match("/augeas#{apath}//error").length > 0
+
+ repos = ['main']
+ repos << 'testing' if testing
+ for repo in repos
+ for aport in aug.match "#{apath}/#{repo}/*"
+ FileAport.new(aug, aport) unless aport.end_with? '/ruby'
+ end
+ end
+
+ for name, attrs in RUBY_SUBPACKAGES[
+ aug.get("#{apath}/main/ruby/APKBUILD/pkgver")
+ ]
+ gem, version, *deps = attrs
+ aport = new name, gem, version
+ for dep in deps
+ aport.add_dependency dep
+ end
+ @@subpackages << aport
+ end
+ end
+
+ @@aports.each_value do |aport|
+ aport.depends do |dep|
+ dep.add_user aport
+ end
+ end
+ end
+
+ def self.get name
+ aport = @@aports[name]
+ raise 'Invalid package name: ' + name unless aport
+ aport
+ end
+
+ def self.ruby_subpkgs
+ for pkg in @@subpackages
+ yield pkg
+ end
+ end
+
+ def initialize name, gem, version
+ @name = name
+ @gem = gem
+ @version = version
+ @depends = []
+ @users = []
+ @@aports[name] = self
+ end
+
+ def add_dependency name
+ @depends << name
+ end
+
+ attr_reader :gem, :name, :version
+
+ def depends
+ for dep in @depends
+ unless @@aports.has_key? dep
+ raise "Dependency for #{@name} does not exist: #{dep}"
+ end
+ yield @@aports[dep]
+ end
+ end
+
+ def users
+ for user in @users
+ yield user
+ end
+ end
+
+ def add_user user
+ @users << user
+ end
+end
+
+class FileAport < Aport
+ def initialize aug, path
+ name = path.split('/')[-1]
+
+ get = proc{ |param|
+ res = aug.get(path + '/APKBUILD/' + param)
+ raise param + ' not defined for ' + name unless res
+ res
+ }
+
+ super name, get.call('_gemname'), get.call('pkgver')
+
+ for dep in `echo #{get.call('depends')}`.split
+ # ruby-gems: workaround for v2.6
+ add_dependency dep if dep.start_with?('ruby-') && dep != 'ruby-gems'
+ end
+ end
+end
+
+
+class Update
+ def initialize
+ @gems = {}
+ @deps = []
+ end
+
+ def require_version name, version
+ gem = assign(Aport.get(name).gem, name)
+ @deps << gem.dependency if gem.require_version version
+ end
+
+ def resolve
+ Aport.ruby_subpkgs do |pkg|
+ require_version pkg.name, pkg.version unless @gems[pkg.gem]
+ end
+
+ def check_deps
+ @gems.clone.each_value do |gem|
+ gem.check_deps
+ end
+ end
+
+ check_deps
+
+ for req in Gem::Resolver.new(@deps).resolve
+ spec = req.spec
+ gem = @gems[spec.name]
+ gem.require_version spec.version.version if gem
+ end
+
+ check_deps
+
+ for name, gem in @gems
+ if gem.updated?
+ gem.aport.users do |user|
+ ugem = @gems[user.gem]
+ if !ugem || ugem.aport.name != user.name
+ Gem::Resolver.new(
+ [gem.dependency, Gem::Dependency.new(user.gem, user.version)]
+ ).resolve
+ end
+ end
+ end
+ end
+ end
+
+ def each