2 * Copyright 2011-2013, Oliver Tappe <zooey@hirschkaefer.de>
3 * Distributed under the terms of the MIT License.
17 #include <ObjectList.h>
21 #include <package/hpkg/HPKGDefs.h>
22 #include <package/hpkg/PackageInfoAttributeValue.h>
23 #include <package/hpkg/RepositoryContentHandler.h>
24 #include <package/hpkg/RepositoryReader.h>
25 #include <package/hpkg/RepositoryWriter.h>
26 #include <package/hpkg/StandardErrorOutput.h>
27 #include <package/PackageInfo.h>
28 #include <package/PackageInfoContentHandler.h>
29 #include <package/RepositoryInfo.h>
31 #include "package_repo.h"
34 using BPackageKit::BHPKG::BRepositoryWriterListener
;
35 using BPackageKit::BHPKG::BRepositoryWriter
;
36 using namespace BPackageKit::BHPKG
;
37 using namespace BPackageKit
;
40 bool operator< (const BPackageInfo
& left
, const BPackageInfo
& right
)
42 if (left
.Name() != right
.Name())
43 return left
.Name() < right
.Name();
44 return left
.Version().Compare(right
.Version()) < 0;
52 typedef std::map
<BPackageInfo
, bool> PackageInfos
;
56 parsePackageListFile(const char* packageListFileName
,
57 BObjectList
<BString
>* packageFileNames
)
59 FILE* packageListFile
= fopen(packageListFileName
, "r");
60 if (packageListFile
== NULL
) {
61 printf("Error: Unable to open %s\n", packageListFileName
);
62 return B_ENTRY_NOT_FOUND
;
65 while (fgets(buffer
, sizeof(buffer
), packageListFile
) != NULL
) {
66 BString
* packageFileName
= new(std::nothrow
) BString(buffer
);
67 if (packageFileName
== NULL
) {
68 printf("Error: Out of memory when reading from %s\n",
70 fclose(packageListFile
);
73 packageFileName
->Trim();
74 packageFileNames
->AddItem(packageFileName
);
76 fclose(packageListFile
);
81 struct PackageInfosCollector
: BRepositoryContentHandler
{
82 PackageInfosCollector(PackageInfos
& packageInfos
,
83 BHPKG::BErrorOutput
* errorOutput
)
85 fPackageInfos(packageInfos
),
86 fErrorOutput(errorOutput
),
89 fPackageInfoContentHandler(fPackageInfo
, fErrorOutput
)
93 virtual status_t
HandlePackage(const char* packageName
)
99 virtual status_t
HandlePackageAttribute(
100 const BPackageInfoAttributeValue
& value
)
102 return fPackageInfoContentHandler
.HandlePackageAttribute(value
);
105 virtual status_t
HandlePackageDone(const char* packageName
)
107 if (fPackageInfo
.InitCheck() != B_OK
) {
108 const BString
& name
= fPackageInfo
.Name();
109 printf("Error: package-info in repository for '%s' is incomplete\n",
110 name
.IsEmpty() ? "<unknown-package>" : name
.String());
113 fPackageInfos
[fPackageInfo
] = false;
117 virtual status_t
HandleRepositoryInfo(const BRepositoryInfo
& repositoryInfo
)
119 fRepositoryInfo
= repositoryInfo
;
123 virtual void HandleErrorOccurred()
127 const BRepositoryInfo
& RepositoryInfo() const
129 return fRepositoryInfo
;
133 PackageInfos
& fPackageInfos
;
134 BHPKG::BErrorOutput
* fErrorOutput
;
135 BRepositoryInfo fRepositoryInfo
;
136 BPackageInfo fPackageInfo
;
137 BPackageInfoContentHandler fPackageInfoContentHandler
;
141 class RepositoryWriterListener
: public BRepositoryWriterListener
{
143 RepositoryWriterListener(bool verbose
, bool quiet
)
144 : fVerbose(verbose
), fQuiet(quiet
)
148 virtual void PrintErrorVarArgs(const char* format
, va_list args
)
150 vfprintf(stderr
, format
, args
);
153 virtual void OnPackageAdded(const BPackageInfo
& packageInfo
)
157 virtual void OnRepositoryInfoSectionDone(uint32 uncompressedSize
)
159 if (fQuiet
|| !fVerbose
)
162 printf("----- Repository Info Section --------------------\n");
163 printf("repository info size: %10" B_PRIu32
" (uncompressed)\n",
167 virtual void OnPackageAttributesSectionDone(uint32 stringCount
,
168 uint32 uncompressedSize
)
170 if (fQuiet
|| !fVerbose
)
173 printf("----- Package Attribute Section -------------------\n");
174 printf("string count: %10" B_PRIu32
"\n", stringCount
);
175 printf("package attributes size: %10" B_PRIu32
" (uncompressed)\n",
179 virtual void OnRepositoryDone(uint32 headerSize
, uint32 repositoryInfoSize
,
180 uint32 licenseCount
, uint32 packageCount
, uint32 packageAttributesSize
,
183 if (fQuiet
|| !fVerbose
)
186 printf("----- Package Repository Info -----\n");
188 printf("embedded license count %10" B_PRIu32
"\n", licenseCount
);
189 printf("package count %10" B_PRIu32
"\n", packageCount
);
190 printf("-----------------------------------\n");
191 printf("header size: %10" B_PRIu32
"\n", headerSize
);
192 printf("repository header size: %10" B_PRIu32
"\n",
194 printf("package attributes size: %10" B_PRIu32
"\n",
195 packageAttributesSize
);
196 printf("total size: %10" B_PRIu64
"\n", totalSize
);
197 printf("-----------------------------------\n");
206 } // anonymous namespace
210 command_update(int argc
, const char* const* argv
)
212 const char* changeToDirectory
= NULL
;
214 bool verbose
= false;
217 static struct option sLongOptions
[] = {
218 { "help", no_argument
, 0, 'h' },
219 { "quiet", no_argument
, 0, 'q' },
220 { "verbose", no_argument
, 0, 'v' },
224 opterr
= 0; // don't print errors
225 int c
= getopt_long(argc
, (char**)argv
, "+C:hqv", sLongOptions
, NULL
);
231 changeToDirectory
= optarg
;
235 print_usage_and_exit(false);
247 print_usage_and_exit(true);
252 // The remaining three arguments are the source and target repository file
253 // plus the package list file.
254 if (optind
+ 3 != argc
)
255 print_usage_and_exit(true);
257 const char* sourceRepositoryFileName
= argv
[optind
++];
258 const char* targetRepositoryFileName
= argv
[optind
++];
259 const char* packageListFileName
= argv
[optind
++];
261 BStandardErrorOutput errorOutput
;
262 RepositoryWriterListener
listener(verbose
, quiet
);
264 BEntry
sourceRepositoryEntry(sourceRepositoryFileName
);
265 if (!sourceRepositoryEntry
.Exists()) {
267 "Error: given source repository file '%s' doesn't exist!\n",
268 sourceRepositoryFileName
);
271 // determine path for 'repo.info' file from given new repository file
272 BString
repositoryInfoFileName(targetRepositoryFileName
);
273 repositoryInfoFileName
.Append(".info");
274 BEntry
repositoryInfoEntry(repositoryInfoFileName
.String());
275 BRepositoryInfo
repositoryInfo(repositoryInfoEntry
);
276 status_t result
= repositoryInfo
.InitCheck();
277 if (result
!= B_OK
) {
279 "Error: can't parse/read repository-info file %s : %s\n",
280 repositoryInfoFileName
.String(), strerror(result
));
284 // open source repository
285 BRepositoryReader
repositoryReader(&errorOutput
);
286 result
= repositoryReader
.Init(sourceRepositoryFileName
);
287 if (result
!= B_OK
) {
289 "Error: can't read from old repository file : %s\n",
294 // collect package infos from source repository
295 PackageInfos packageInfos
;
296 PackageInfosCollector
packageInfosCollector(packageInfos
, &errorOutput
);
297 result
= repositoryReader
.ParseContent(&packageInfosCollector
);
298 if (result
!= B_OK
) {
300 "Error: couldn't fetch package infos from old repository : %s\n",
305 // create new repository
306 BRepositoryWriter
repositoryWriter(&listener
, &repositoryInfo
);
307 BString
tempRepositoryFileName(targetRepositoryFileName
);
308 tempRepositoryFileName
+= ".___new___";
309 if ((result
= repositoryWriter
.Init(tempRepositoryFileName
.String()))
311 listener
.PrintError("Error: can't initialize repository-writer : %s\n",
316 BEntry
tempRepositoryFile(tempRepositoryFileName
.String());
317 BPath
targetRepositoryFilePath(targetRepositoryFileName
);
319 BObjectList
<BString
> packageNames(100, true);
320 if ((result
= parsePackageListFile(packageListFileName
, &packageNames
))
323 "Error: Failed to read package-list-file \"%s\": %s\n",
324 packageListFileName
, strerror(result
));
328 // change directory, if requested
329 if (changeToDirectory
!= NULL
) {
330 if (chdir(changeToDirectory
) != 0) {
332 "Error: Failed to change the current working directory to "
333 "\"%s\": %s\n", changeToDirectory
, strerror(errno
));
338 // add all given package files
339 for (int i
= 0; i
< packageNames
.CountItems(); ++i
) {
340 BPackageInfo packageInfo
;
341 if ((result
= packageInfo
.ReadFromPackageFile(
342 packageNames
.ItemAt(i
)->String())) != B_OK
) {
344 "Error: Failed to read package-info from \"%s\": %s\n",
345 packageNames
.ItemAt(i
)->String(), strerror(result
));
348 PackageInfos::iterator infoIter
= packageInfos
.find(packageInfo
);
349 if (infoIter
!= packageInfos
.end()) {
350 infoIter
->second
= true;
351 if ((result
= repositoryWriter
.AddPackageInfo(infoIter
->first
))
355 printf("keeping '%s-%s'\n", infoIter
->first
.Name().String(),
356 infoIter
->first
.Version().ToString().String());
359 BEntry
entry(packageNames
.ItemAt(i
)->String());
360 if ((result
= repositoryWriter
.AddPackage(entry
)) != B_OK
)
363 printf("added '%s' ...\n",
364 packageNames
.ItemAt(i
)->String());
369 // tell about packages dropped from repository
370 PackageInfos::const_iterator infoIter
;
371 for (infoIter
= packageInfos
.begin(); infoIter
!= packageInfos
.end();
373 if (!infoIter
->second
) {
374 printf("dropped '%s-%s'\n", infoIter
->first
.Name().String(),
375 infoIter
->first
.Version().ToString().String());
380 // write the repository
381 result
= repositoryWriter
.Finish();
385 result
= tempRepositoryFile
.Rename(targetRepositoryFilePath
.Leaf(), true);
386 if (result
!= B_OK
) {
387 printf("Error: unable to rename repository %s to %s - %s\n",
388 tempRepositoryFileName
.String(), targetRepositoryFileName
,
394 printf("\nsuccessfully created repository '%s'\n",
395 targetRepositoryFileName
);