1 /* 2 * Copyright 2013, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold <ingo_weinhold@gmx.de> 7 */ 8 9 10 #include <package/manager/RepositoryBuilder.h> 11 12 #include <errno.h> 13 #include <dirent.h> 14 15 #include <Entry.h> 16 #include <package/RepositoryCache.h> 17 #include <Path.h> 18 19 #include <AutoDeleter.h> 20 21 #include "PackageManagerUtils.h" 22 23 24 namespace BPackageKit { 25 26 namespace BManager { 27 28 namespace BPrivate { 29 30 31 namespace { 32 33 34 class PackageInfoErrorListener : public BPackageInfo::ParseErrorListener { 35 public: 36 PackageInfoErrorListener(const char* context) 37 { 38 } 39 40 virtual void OnError(const BString& message, int line, int column) 41 { 42 fErrors << BString().SetToFormat("%s: parse error in line %d:%d: %s\n", 43 fContext, line, column, message.String()); 44 } 45 46 const BString& Errors() const 47 { 48 return fErrors; 49 } 50 51 private: 52 const char* fContext; 53 BString fErrors; 54 }; 55 56 57 } // unnamed namespace 58 59 60 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository) 61 : 62 fRepository(repository), 63 fErrorName(repository.Name()), 64 fPackagePaths(NULL) 65 { 66 } 67 68 69 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository, 70 const BString& name, const BString& errorName) 71 : 72 fRepository(repository), 73 fErrorName(errorName.IsEmpty() ? name : errorName), 74 fPackagePaths(NULL) 75 { 76 status_t error = fRepository.SetTo(name); 77 if (error != B_OK) 78 DIE(error, "failed to init %s repository", fErrorName.String()); 79 } 80 81 82 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository, 83 const BRepositoryConfig& config) 84 : 85 fRepository(repository), 86 fErrorName(fRepository.Name()), 87 fPackagePaths(NULL) 88 { 89 status_t error = fRepository.SetTo(config); 90 if (error != B_OK) 91 DIE(error, "failed to init %s repository", fErrorName.String()); 92 } 93 94 95 BRepositoryBuilder::BRepositoryBuilder(BSolverRepository& repository, 96 const BRepositoryCache& cache, const BString& errorName) 97 : 98 fRepository(repository), 99 fErrorName(errorName.IsEmpty() ? cache.Info().Name() : errorName), 100 fPackagePaths(NULL) 101 { 102 status_t error = fRepository.SetTo(cache); 103 if (error != B_OK) 104 DIE(error, "failed to init %s repository", fErrorName.String()); 105 fErrorName = fRepository.Name(); 106 } 107 108 109 BRepositoryBuilder& 110 BRepositoryBuilder::SetPackagePathMap(BPackagePathMap* packagePaths) 111 { 112 fPackagePaths = packagePaths; 113 return *this; 114 } 115 116 117 BRepositoryBuilder& 118 BRepositoryBuilder::AddPackage(const BPackageInfo& info, 119 const char* packageErrorName, BSolverPackage** _package) 120 { 121 status_t error = fRepository.AddPackage(info, _package); 122 if (error != B_OK) { 123 DIE(error, "failed to add %s to %s repository", 124 packageErrorName != NULL 125 ? packageErrorName 126 : (BString("package ") << info.Name()).String(), 127 fErrorName.String()); 128 } 129 return *this; 130 } 131 132 133 BRepositoryBuilder& 134 BRepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package) 135 { 136 // read a package info from the (HPKG or package info) file 137 BPackageInfo packageInfo; 138 139 size_t pathLength = strlen(path); 140 status_t error; 141 PackageInfoErrorListener errorListener(path); 142 if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) { 143 // a package file 144 error = packageInfo.ReadFromPackageFile(path); 145 } else { 146 // a package info file (supposedly) 147 error = packageInfo.ReadFromConfigFile(BEntry(path, true), 148 &errorListener); 149 } 150 151 if (error != B_OK) { 152 DIE_DETAILS(errorListener.Errors(), error, 153 "failed to read package info from \"%s\"", path); 154 } 155 156 // add the package 157 BSolverPackage* package; 158 AddPackage(packageInfo, path, &package); 159 160 // enter the package path in the path map, if given 161 if (fPackagePaths != NULL) 162 (*fPackagePaths)[package] = path; 163 164 if (_package != NULL) 165 *_package = package; 166 167 return *this; 168 } 169 170 171 BRepositoryBuilder& 172 BRepositoryBuilder::AddPackages(BPackageInstallationLocation location, 173 const char* locationErrorName) 174 { 175 status_t error = fRepository.AddPackages(location); 176 if (error != B_OK) { 177 DIE(error, "failed to add %s packages to %s repository", 178 locationErrorName, fErrorName.String()); 179 } 180 return *this; 181 } 182 183 184 BRepositoryBuilder& 185 BRepositoryBuilder::AddPackagesDirectory(const char* path) 186 { 187 // open directory 188 DIR* dir = opendir(path); 189 if (dir == NULL) 190 DIE(errno, "failed to open package directory \"%s\"", path); 191 CObjectDeleter<DIR, int> dirCloser(dir, &closedir); 192 193 // iterate through directory entries 194 while (dirent* entry = readdir(dir)) { 195 // skip "." and ".." 196 const char* name = entry->d_name; 197 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) 198 continue; 199 200 // stat() the entry and skip any non-file 201 BPath entryPath; 202 status_t error = entryPath.SetTo(path, name); 203 if (error != B_OK) 204 DIE(errno, "failed to construct path"); 205 206 struct stat st; 207 if (stat(entryPath.Path(), &st) != 0) 208 DIE(errno, "failed to stat() %s", entryPath.Path()); 209 210 if (!S_ISREG(st.st_mode)) 211 continue; 212 213 AddPackage(entryPath.Path()); 214 } 215 216 return *this; 217 } 218 219 220 BRepositoryBuilder& 221 BRepositoryBuilder::AddToSolver(BSolver* solver, bool isInstalled) 222 { 223 fRepository.SetInstalled(isInstalled); 224 225 status_t error = solver->AddRepository(&fRepository); 226 if (error != B_OK) { 227 DIE(error, "failed to add %s repository to solver", 228 fErrorName.String()); 229 } 230 return *this; 231 } 232 233 234 } // namespace BPrivate 235 236 } // namespace BManager 237 238 } // namespace BPackageKit 239