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
31 using namespace BPackageKit;
32 using namespace BPackageKit::BManager::BPrivate;
33
34
LocalRepositoryUpdateProcess(Model * model,bool force)35 LocalRepositoryUpdateProcess::LocalRepositoryUpdateProcess(
36 Model *model, bool force)
37 :
38 AbstractProcess(),
39 fModel(model),
40 fForce(force)
41 {
42 }
43
44
~LocalRepositoryUpdateProcess()45 LocalRepositoryUpdateProcess::~LocalRepositoryUpdateProcess()
46 {
47 }
48
49
50 const char*
Name() const51 LocalRepositoryUpdateProcess::Name() const
52 {
53 return "LocalRepositoryUpdateProcess";
54 }
55
56
57 const char*
Description() const58 LocalRepositoryUpdateProcess::Description() const
59 {
60 return B_TRANSLATE("Fetching remote repository data");
61 }
62
63
64 status_t
RunInternal()65 LocalRepositoryUpdateProcess::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
100 bool
_ShouldRunForRepositoryName(const BString & repoName,BPackageKit::BPackageRoster & roster,BPackageKit::BRepositoryCache * cache)101 LocalRepositoryUpdateProcess::_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
130 status_t
_RunForRepositoryName(const BString & repoName,BPackageKit::BContext & context,BPackageKit::BPackageRoster & roster,BPackageKit::BRepositoryCache * cache)131 LocalRepositoryUpdateProcess::_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
160 void
_NotifyError(const BString & error) const161 LocalRepositoryUpdateProcess::_NotifyError(const BString& error) const
162 {
163 _NotifyError(error, "");
164 }
165
166
167 void
_NotifyError(const BString & error,const BString & details) const168 LocalRepositoryUpdateProcess::_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