#include <iostream>
#include <list>
#include <vector>
-
+#include <fstream>
#include <boost/lexical_cast.hpp>
#include "zypp/base/Logger.h"
#include "zypp/ZYppFactory.h"
#include "zypp/ZConfig.h"
+#include "zypp/TmpPath.h"
+
#include "zypp/media/MediaAria2c.h"
#include "zypp/media/proxyinfo/ProxyInfos.h"
#include "zypp/media/ProxyInfo.h"
*/
void fillAriaCmdLine( const string &ariaver,
const TransferSettings &s,
+ filesystem::TmpPath &credentials,
const Url &url,
const Pathname &destination,
ExternalProgram::Arguments &args )
{
+
+ // options that are not passed in the command line
+ // like credentials, every string is in the
+ // opt=val format
+ list<string> file_options;
+
args.push_back(ARIA_BINARY);
args.push_back(str::form("--user-agent=%s", s.userAgentString().c_str()));
args.push_back("--summary-interval=1");
else
{
if ( url.getScheme() == "ftp" )
- args.push_back(str::form("--ftp-user=%s", s.username().c_str() ));
+ file_options.push_back(str::form("ftp-user=%s", s.username().c_str() ));
else if ( url.getScheme() == "http" ||
url.getScheme() == "https" )
- args.push_back(str::form("--http-user=%s", s.username().c_str() ));
+ file_options.push_back(str::form("http-user=%s", s.username().c_str() ));
if ( s.password().size() )
{
if ( url.getScheme() == "ftp" )
- args.push_back(str::form("--ftp-passwd=%s", s.password().c_str() ));
+ file_options.push_back(str::form("ftp-passwd=%s", s.password().c_str() ));
else if ( url.getScheme() == "http" ||
url.getScheme() == "https" )
- args.push_back(str::form("--http-passwd=%s", s.password().c_str() ));
+ file_options.push_back(str::form("http-passwd=%s", s.password().c_str() ));
}
}
args.push_back(str::form("--http-proxy=%s", s.proxy().c_str() ));
if ( ! s.proxyUsername().empty() )
{
- args.push_back(str::form("--http-proxy-user=%s", s.proxyUsername().c_str() ));
+ file_options.push_back(str::form("http-proxy-user=%s", s.proxyUsername().c_str() ));
if ( ! s.proxyPassword().empty() )
- args.push_back(str::form("--http-proxy-passwd=%s", s.proxyPassword().c_str() ));
+ file_options.push_back(str::form("http-proxy-passwd=%s", s.proxyPassword().c_str() ));
}
}
if ( ! destination.empty() )
args.push_back(str::form("--dir=%s", destination.c_str()));
+ // now append the file if there are hidden options
+ if ( ! file_options.empty() )
+ {
+ filesystem::TmpFile tmp;
+ ofstream outs( tmp.path().c_str() );
+ for_( it, file_options.begin(), file_options.end() )
+ outs << *it << endl;
+ outs.close();
+
+ credentials = tmp;
+ args.push_back(str::form("--conf-path=%s", credentials.path().c_str()));
+ }
+
args.push_back(url.asString().c_str());
}
ExternalProgram::Arguments args;
- fillAriaCmdLine(_aria2cVersion, _settings, fileurl, target.dirname(), args);
+ filesystem::TmpPath credentials;
+ fillAriaCmdLine(_aria2cVersion, _settings, credentials, fileurl, target.dirname(), args);
do
{
// (bnc #513944) [#1 SIZE:8.3MiB/10.1MiB(82%) CN:5 SPD:3.8MiBs]
// we save it until we find a string with FILE: later
string progressLine;
+ int progress = 0;
// file line, which tell which file is the previous progress
// ie: FILE: ./packages.FL.gz
double average_speed = 0;
// here we capture aria output exceptions
vector<string> ariaExceptions;
+ // TODO: Detect partial downloads!
+ bool partialDownload = false; // Whether it makes sense to retry with --continue!
+
//Process response
for(std::string ariaResponse( aria.receiveLine());
ariaResponse.length();
else if ( str::hasPrefix(line, "FILE: ") )
{
// get the FILE name
- Pathname theFile(line.substr(6, line.size()));
+ string theFile(line.substr(6, line.size()));
// is the report about the filename we are downloading?
// aria may report progress about metalinks, torrent and
// other stuff which is not the main transfer
- if ( theFile == target )
+ // the reported file is the url before the server emits a response
+ // and then is reported as the target file
+ if ( Pathname(theFile) == target || theFile == fileurl.asCompleteString() )
{
// once we find the FILE: line, progress has to be
// non empty
if ( ! progressLine.empty() )
{
// get the percentage (progress) data
- int progress = 0;
+ progress = 0;
size_t left_bound = progressLine.find('(',0) + 1;
size_t count = progressLine.find('%',left_bound) - left_bound;
string progressStr = progressLine.substr(left_bound, count);
case 1: // unknown
default:
{
+ if ( partialDownload )
+ {
+ // Ask for retry on partial downloads, when it makes sense to retry with --continue!
+ // Other errors are handled by the layers above.
+ MediaException e(str::form(_("Download interrupted at %d%%"), progress ));
+ for_(it, ariaExceptions.begin(), ariaExceptions.end())
+ e.addHistory(*it);
+
+ DownloadProgressReport::Action action = report->problem( _url, DownloadProgressReport::ERROR, e.asUserHistory() );
+ if ( action == DownloadProgressReport::RETRY )
+ {
+ retry = true;
+ continue;
+ }
+ }
+
// TranslatorExplanation: Failed to download <FILENAME> from <SERVERURL>.
MediaException e(str::form(_("Failed to download %s from %s"), filename.c_str(), _url.asString().c_str()));
for_(it, ariaExceptions.begin(), ariaExceptions.end())
return false;
}
-
void MediaAria2c::getDirInfo( std::list<std::string> & retlist,
const Pathname & dirname, bool dots ) const
{