1/*
2 * Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6
7#include "LocalRepositoryUpdateProcess.h"
8
9#include <Catalog.h>
10#include <Roster.h>
11#include <String.h>
12#include <StringList.h>
13
14#include <package/Context.h>
15#include <package/manager/Exceptions.h>
16#include <package/PackageRoster.h>
17#include <package/RefreshRepositoryRequest.h>
18
19#include "App.h"
20#include "AppUtils.h"
21#include "DecisionProvider.h"
22#include "JobStateListener.h"
23#include "Logger.h"
24#include "HaikuDepotConstants.h"
25
26
27#undef B_TRANSLATION_CONTEXT
28#define B_TRANSLATION_CONTEXT "LocalRepositoryUpdateProcess"
29
30
31using namespace BPackageKit;
32using namespace BPackageKit::BManager::BPrivate;
33
34
35LocalRepositoryUpdateProcess::LocalRepositoryUpdateProcess(
36	Model *model, bool force)
37	:
38	AbstractProcess(),
39	fModel(model),
40	fForce(force)
41{
42}
43
44
45LocalRepositoryUpdateProcess::~LocalRepositoryUpdateProcess()
46{
47}
48
49
50const char*
51LocalRepositoryUpdateProcess::Name() const
52{
53	return "LocalRepositoryUpdateProcess";
54}
55
56
57const char*
58LocalRepositoryUpdateProcess::Description() const
59{
60	return B_TRANSLATE("Fetching remote repository data");
61}
62
63
64status_t
65LocalRepositoryUpdateProcess::RunInternal()
66{
67	BPackageRoster roster;
68	BStringList repoNames;
69	HDINFO("[%s] will update local repositories' caches", Name());
70
71	status_t result = roster.GetRepositoryNames(repoNames);
72
73	if (result == B_OK) {
74		DecisionProvider decisionProvider;
75		JobStateListener listener;
76		BContext context(decisionProvider, listener);
77		BRepositoryCache cache;
78
79		for (
80			int32 i = 0;
81			result == B_OK && i < repoNames.CountStrings() && !WasStopped();
82			++i) {
83			result = _RunForRepositoryName(repoNames.StringAt(i), context,
84				roster, &cache);
85		}
86	} else {
87		_NotifyError(strerror(result));
88		result = B_ERROR;
89	}
90
91	if (result == B_OK) {
92		HDINFO("[%s] did update %" B_PRIi32 " local repositories' caches",
93			Name(), repoNames.CountStrings());
94	}
95
96	return result;
97}
98
99
100bool
101LocalRepositoryUpdateProcess::_ShouldRunForRepositoryName(
102	const BString& repoName, BPackageKit::BPackageRoster& roster,
103	BPackageKit::BRepositoryCache* cache)
104{
105	if (fForce) {
106		HDINFO("[%s] am refreshing cache for repo [%s] as it was forced",
107			Name(), repoName.String());
108		return true;
109	}
110
111	if (roster.GetRepositoryCache(repoName, cache) != B_OK) {
112		HDINFO("[%s] am updating cache for repo [%s] as there was no cache",
113			Name(), repoName.String());
114		return true;
115	}
116
117	if (static_cast<App*>(be_app)->IsFirstRun()) {
118		HDINFO("[%s] am updating cache for repo [%s] as this is the first"
119			" time that the application has run", Name(), repoName.String());
120		return true;
121	}
122
123	HDDEBUG("[%s] skipped update local repo [%s] cache", Name(),
124		repoName.String());
125
126	return false;
127}
128
129
130status_t
131LocalRepositoryUpdateProcess::_RunForRepositoryName(const BString& repoName,
132	BPackageKit::BContext& context, BPackageKit::BPackageRoster& roster,
133	BPackageKit::BRepositoryCache* cache)
134{
135	status_t result = B_ERROR;
136	BRepositoryConfig repoConfig;
137	result = roster.GetRepositoryConfig(repoName, &repoConfig);
138	if (result == B_OK) {
139		if (_ShouldRunForRepositoryName(repoName, roster, cache)) {
140			try {
141				BRefreshRepositoryRequest refreshRequest(context, repoConfig);
142				result = refreshRequest.Process();
143				HDINFO("[%s] did update local repo [%s] cache", Name(),
144					repoName.String());
145				result = B_OK;
146			} catch (BFatalErrorException& ex) {
147				_NotifyError(ex.Message(), ex.Details());
148			} catch (BException& ex) {
149				_NotifyError(ex.Message());
150			}
151		}
152	} else {
153		_NotifyError(strerror(result));
154	}
155
156	return result;
157}
158
159
160void
161LocalRepositoryUpdateProcess::_NotifyError(const BString& error) const
162{
163	_NotifyError(error, "");
164}
165
166
167void
168LocalRepositoryUpdateProcess::_NotifyError(const BString& error,
169	const BString& details) const
170{
171	HDINFO("an error has arisen updating the local repositories : %s",
172		error.String());
173
174	BString alertText(B_TRANSLATE("An error occurred while refreshing the "
175		"repository: %error%"));
176	alertText.ReplaceFirst("%error%", error);
177
178	if (!details.IsEmpty()) {
179		alertText.Append(" (");
180		alertText.Append(details);
181		alertText.Append(")");
182	}
183
184	AppUtils::NotifySimpleError(
185		B_TRANSLATE("Repository update error"),
186		alertText);
187}
188