Support customization of fetchcommand and resumecommand in
binrepos.conf, allowing customized authentication mechanisms for
each repository.

Bug: https://bugs.gentoo.org/661332
Signed-off-by: Zac Medico <zmed...@gentoo.org>
---
 lib/_emerge/BinpkgFetcher.py  | 29 +++++++++++++++++++----------
 lib/portage/binrepo/config.py |  2 ++
 lib/portage/dbapi/bintree.py  | 34 +++++++++++++++++++++++++---------
 man/portage.5                 | 14 ++++++++++++++
 4 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/lib/_emerge/BinpkgFetcher.py b/lib/_emerge/BinpkgFetcher.py
index 218d4d2ab..9a96bde28 100644
--- a/lib/_emerge/BinpkgFetcher.py
+++ b/lib/_emerge/BinpkgFetcher.py
@@ -96,14 +96,17 @@ class _BinpkgFetcherProcess(SpawnProcess):
 
                # urljoin doesn't work correctly with
                # unrecognized protocols like sftp
+               fetchcommand = None
+               resumecommand = None
                if bintree._remote_has_index:
-                       instance_key = bintree.dbapi._instance_key(pkg.cpv)
-                       rel_uri = bintree._remotepkgs[instance_key].get("PATH")
+                       remote_metadata = 
bintree._remotepkgs[bintree.dbapi._instance_key(pkg.cpv)]
+                       rel_uri = remote_metadata.get("PATH")
                        if not rel_uri:
                                rel_uri = pkg.cpv + ".tbz2"
-                       remote_base_uri = bintree._remotepkgs[
-                               instance_key]["BASE_URI"]
+                       remote_base_uri = remote_metadata["BASE_URI"]
                        uri = remote_base_uri.rstrip("/") + "/" + 
rel_uri.lstrip("/")
+                       fetchcommand = remote_metadata.get('FETCHCOMMAND')
+                       resumecommand = remote_metadata.get('RESUMECOMMAND')
                else:
                        uri = settings["PORTAGE_BINHOST"].rstrip("/") + \
                                "/" + pkg.pf + ".tbz2"
@@ -114,13 +117,19 @@ class _BinpkgFetcherProcess(SpawnProcess):
                        self._async_wait()
                        return
 
-               protocol = urllib_parse_urlparse(uri)[0]
-               fcmd_prefix = "FETCHCOMMAND"
+               fcmd = None
                if resume:
-                       fcmd_prefix = "RESUMECOMMAND"
-               fcmd = settings.get(fcmd_prefix + "_" + protocol.upper())
-               if not fcmd:
-                       fcmd = settings.get(fcmd_prefix)
+                       fcmd = resumecommand
+               else:
+                       fcmd = fetchcommand
+               if fcmd is None:
+                       protocol = urllib_parse_urlparse(uri)[0]
+                       fcmd_prefix = "FETCHCOMMAND"
+                       if resume:
+                               fcmd_prefix = "RESUMECOMMAND"
+                       fcmd = settings.get(fcmd_prefix + "_" + 
protocol.upper())
+                       if not fcmd:
+                               fcmd = settings.get(fcmd_prefix)
 
                fcmd_vars = {
                        "DISTDIR" : os.path.dirname(pkg_path),
diff --git a/lib/portage/binrepo/config.py b/lib/portage/binrepo/config.py
index aa3ff7a77..0c01f6fae 100644
--- a/lib/portage/binrepo/config.py
+++ b/lib/portage/binrepo/config.py
@@ -15,7 +15,9 @@ class BinRepoConfig:
        __slots__ = (
                'name',
                'name_fallback',
+               'fetchcommand',
                'priority',
+               'resumecommand',
                'sync_uri',
        )
        def __init__(self, opts):
diff --git a/lib/portage/dbapi/bintree.py b/lib/portage/dbapi/bintree.py
index a96183561..ebc6765b6 100644
--- a/lib/portage/dbapi/bintree.py
+++ b/lib/portage/dbapi/bintree.py
@@ -382,10 +382,10 @@ class binarytree:
                        self._pkgindex_keys.update(["CPV", "SIZE"])
                        self._pkgindex_aux_keys = \
                                ["BASE_URI", "BDEPEND", "BUILD_ID", 
"BUILD_TIME", "CHOST",
-                               "DEFINED_PHASES", "DEPEND", "DESCRIPTION", 
"EAPI",
+                               "DEFINED_PHASES", "DEPEND", "DESCRIPTION", 
"EAPI", "FETCHCOMMAND",
                                "IUSE", "KEYWORDS", "LICENSE", "PDEPEND",
                                "PKGINDEX_URI", "PROPERTIES", "PROVIDES",
-                               "RDEPEND", "repository", "REQUIRES", "RESTRICT",
+                               "RDEPEND", "repository", "REQUIRES", 
"RESTRICT", "RESUMECOMMAND",
                                "SIZE", "SLOT", "USE"]
                        self._pkgindex_aux_keys = list(self._pkgindex_aux_keys)
                        self._pkgindex_use_evaluated_keys = \
@@ -972,7 +972,7 @@ class binarytree:
 
                                # Don't use urlopen for https, unless
                                # PEP 476 is supported (bug #469888).
-                               if parsed_url.scheme not in ('https',) or 
_have_pep_476():
+                               if repo.fetchcommand is None and 
(parsed_url.scheme not in ('https',) or _have_pep_476()):
                                        try:
                                                f = _urlopen(url, 
if_modified_since=local_timestamp)
                                                if hasattr(f, 'headers') and 
f.headers.get('timestamp', ''):
@@ -997,7 +997,7 @@ class binarytree:
 
                                        path = parsed_url.path.rstrip("/") + 
"/Packages"
 
-                                       if parsed_url.scheme == 'ssh':
+                                       if repo.fetchcommand is None and 
parsed_url.scheme == 'ssh':
                                                # Use a pipe so that we can 
terminate the download
                                                # early if we detect that the 
TIMESTAMP header
                                                # matches that of the cached 
Packages file.
@@ -1016,12 +1016,15 @@ class binarytree:
                                                        stdout=subprocess.PIPE)
                                                f = proc.stdout
                                        else:
-                                               setting = 'FETCHCOMMAND_' + 
parsed_url.scheme.upper()
-                                               fcmd = 
self.settings.get(setting)
-                                               if not fcmd:
-                                                       fcmd = 
self.settings.get('FETCHCOMMAND')
+                                               if repo.fetchcommand is None:
+                                                       setting = 
'FETCHCOMMAND_' + parsed_url.scheme.upper()
+                                                       fcmd = 
self.settings.get(setting)
                                                        if not fcmd:
-                                                               raise 
EnvironmentError("FETCHCOMMAND is unset")
+                                                               fcmd = 
self.settings.get('FETCHCOMMAND')
+                                                               if not fcmd:
+                                                                       raise 
EnvironmentError("FETCHCOMMAND is unset")
+                                               else:
+                                                       fcmd = repo.fetchcommand
 
                                                fd, tmp_filename = 
tempfile.mkstemp()
                                                tmp_dirname, tmp_basename = 
os.path.split(tmp_filename)
@@ -1135,6 +1138,19 @@ class binarytree:
                                        d["CPV"] = cpv
                                        d["BASE_URI"] = remote_base_uri
                                        d["PKGINDEX_URI"] = url
+                                       # FETCHCOMMAND and RESUMECOMMAND may be 
specified
+                                       # by binrepos.conf, and otherwise 
ensure that they
+                                       # do not propagate from the Packages 
index since
+                                       # it may be unsafe to execute remotely 
specified
+                                       # commands.
+                                       if repo.fetchcommand is None:
+                                               d.pop('FETCHCOMMAND', None)
+                                       else:
+                                               d['FETCHCOMMAND'] = 
repo.fetchcommand
+                                       if repo.resumecommand is None:
+                                               d.pop('RESUMECOMMAND', None)
+                                       else:
+                                               d['RESUMECOMMAND'] = 
repo.resumecommand
                                        
self._remotepkgs[self.dbapi._instance_key(cpv)] = d
                                        self.dbapi.cpv_inject(cpv)
 
diff --git a/man/portage.5 b/man/portage.5
index 890a22adb..9c88bc3dc 100644
--- a/man/portage.5
+++ b/man/portage.5
@@ -634,6 +634,20 @@ is intended to be used as a replacement for the 
\fBmake.conf\fR(5)
 \- attributes are specified in "${attribute} = ${value}" format
 .fi
 
+.RS
+.I Attributes supported in DEFAULT section:
+.RS
+.TP
+.B fetchcommand
+Specifies a \fBFETCHCOMMAND\fR used to fetch files from a repository,
+overriding the value from \fBmake.conf\fR(5).
+.TP
+.B resumecommand
+Specifies a \fBRESUMECOMMAND\fR used to fetch files from a repository,
+overriding the value from \fBmake.conf\fR(5).
+.RE
+.RE
+
 .RS
 .I Attributes supported in sections of repositories:
 .RS
-- 
2.25.3


Reply via email to