1 /* 2 * Copyright 2017-2018, Andrew Lindesay <apl@lindesay.co.nz>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ServerRepositoryDataUpdateProcess.h" 8 9 #include <stdio.h> 10 #include <sys/stat.h> 11 #include <time.h> 12 13 #include <AutoDeleter.h> 14 #include <Catalog.h> 15 #include <FileIO.h> 16 #include <Url.h> 17 18 #include "ServerSettings.h" 19 #include "StorageUtils.h" 20 #include "Logger.h" 21 #include "DumpExportRepository.h" 22 #include "DumpExportRepositorySource.h" 23 #include "DumpExportRepositoryJsonListener.h" 24 25 26 #undef B_TRANSLATION_CONTEXT 27 #define B_TRANSLATION_CONTEXT "ServerRepositoryDataUpdateProcess" 28 29 30 /*! This repository listener (not at the JSON level) is feeding in the 31 repositories as they are parsed and processing them. Processing 32 includes finding the matching depot record and coupling the data 33 from the server with the data about the depot. 34 */ 35 36 class DepotMatchingRepositoryListener : 37 public DumpExportRepositoryListener, public DepotMapper { 38 public: 39 DepotMatchingRepositoryListener(Model* model, 40 Stoppable* stoppable); 41 virtual ~DepotMatchingRepositoryListener(); 42 43 virtual DepotInfo MapDepot(const DepotInfo& depot, void *context); 44 virtual bool Handle(DumpExportRepository* item); 45 virtual void Complete(); 46 47 private: 48 void NormalizeUrl(BUrl& url) const; 49 bool IsUnassociatedDepotByUrl( 50 const DepotInfo& depotInfo, 51 const BString& urlStr) const; 52 53 int32 IndexOfUnassociatedDepotByUrl( 54 const BString& url) const; 55 56 Model* fModel; 57 Stoppable* fStoppable; 58 }; 59 60 61 DepotMatchingRepositoryListener::DepotMatchingRepositoryListener( 62 Model* model, Stoppable* stoppable) 63 : 64 fModel(model), 65 fStoppable(stoppable) 66 { 67 } 68 69 70 DepotMatchingRepositoryListener::~DepotMatchingRepositoryListener() 71 { 72 } 73 74 75 struct repository_and_repository_source { 76 DumpExportRepository* repository; 77 DumpExportRepositorySource* repositorySource; 78 }; 79 80 81 /*! This is invoked as a result of logic in 'Handle(..)' that requests that the 82 model call this method with the requested DepotInfo instance. 83 */ 84 85 DepotInfo 86 DepotMatchingRepositoryListener::MapDepot(const DepotInfo& depot, void *context) 87 { 88 repository_and_repository_source* repositoryAndRepositorySource = 89 (repository_and_repository_source*) context; 90 BString* repositoryCode = 91 repositoryAndRepositorySource->repository->Code(); 92 BString* repositorySourceCode = 93 repositoryAndRepositorySource->repositorySource->Code(); 94 95 DepotInfo modifiedDepotInfo(depot); 96 modifiedDepotInfo.SetWebAppRepositoryCode(BString(*repositoryCode)); 97 modifiedDepotInfo.SetWebAppRepositorySourceCode( 98 BString(*repositorySourceCode)); 99 100 if (Logger::IsDebugEnabled()) { 101 printf("[DepotMatchingRepositoryListener] associated depot [%s] (%s) " 102 "with server repository source [%s] (%s)\n", 103 modifiedDepotInfo.Name().String(), 104 modifiedDepotInfo.URL().String(), 105 repositorySourceCode->String(), 106 repositoryAndRepositorySource->repositorySource->Url()->String()); 107 } else { 108 printf("[DepotMatchingRepositoryListener] associated depot [%s] with " 109 "server repository source [%s]\n", 110 modifiedDepotInfo.Name().String(), 111 repositorySourceCode->String()); 112 } 113 114 return modifiedDepotInfo; 115 } 116 117 118 bool 119 DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository) 120 { 121 int32 i; 122 123 for (i = 0; i < repository->CountRepositorySources(); i++) { 124 repository_and_repository_source repositoryAndRepositorySource; 125 repositoryAndRepositorySource.repository = repository; 126 repositoryAndRepositorySource.repositorySource = 127 repository->RepositorySourcesItemAt(i); 128 129 BString* repoInfoURL = repositoryAndRepositorySource 130 .repositorySource->RepoInfoUrl(); 131 132 if (!repoInfoURL->IsEmpty()) { 133 fModel->ReplaceDepotByUrl(*repoInfoURL, this, 134 &repositoryAndRepositorySource); 135 } 136 } 137 138 return !fStoppable->WasStopped(); 139 } 140 141 142 void 143 DepotMatchingRepositoryListener::Complete() 144 { 145 } 146 147 148 ServerRepositoryDataUpdateProcess::ServerRepositoryDataUpdateProcess( 149 Model* model, 150 uint32 serverProcessOptions) 151 : 152 AbstractSingleFileServerProcess(serverProcessOptions), 153 fModel(model) 154 { 155 } 156 157 158 ServerRepositoryDataUpdateProcess::~ServerRepositoryDataUpdateProcess() 159 { 160 } 161 162 163 const char* 164 ServerRepositoryDataUpdateProcess::Name() const 165 { 166 return "ServerRepositoryDataUpdateProcess"; 167 } 168 169 170 const char* 171 ServerRepositoryDataUpdateProcess::Description() const 172 { 173 return B_TRANSLATE("Synchronizing meta-data about repositories"); 174 } 175 176 177 BString 178 ServerRepositoryDataUpdateProcess::UrlPathComponent() 179 { 180 return BString("/__repository/all-en.json.gz"); 181 } 182 183 184 status_t 185 ServerRepositoryDataUpdateProcess::GetLocalPath(BPath& path) const 186 { 187 return fModel->DumpExportRepositoryDataPath(path); 188 } 189 190 191 status_t 192 ServerRepositoryDataUpdateProcess::ProcessLocalData() 193 { 194 DepotMatchingRepositoryListener* itemListener = 195 new DepotMatchingRepositoryListener(fModel, this); 196 ObjectDeleter<DepotMatchingRepositoryListener> 197 itemListenerDeleter(itemListener); 198 199 BulkContainerDumpExportRepositoryJsonListener* listener = 200 new BulkContainerDumpExportRepositoryJsonListener(itemListener); 201 ObjectDeleter<BulkContainerDumpExportRepositoryJsonListener> 202 listenerDeleter(listener); 203 204 BPath localPath; 205 status_t result = GetLocalPath(localPath); 206 207 if (result != B_OK) 208 return result; 209 210 result = ParseJsonFromFileWithListener(listener, localPath); 211 212 if (result != B_OK) 213 return result; 214 215 return listener->ErrorStatus(); 216 } 217 218 219 status_t 220 ServerRepositoryDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const 221 { 222 return GetLocalPath(path); 223 } 224 225 226 void 227 ServerRepositoryDataUpdateProcess::GetStandardMetaDataJsonPath( 228 BString& jsonPath) const 229 { 230 jsonPath.SetTo("$.info"); 231 } 232