root/src/bin/package_repo/command_list.cpp
/*
 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
 * Distributed under the terms of the MIT License.
 */


#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <package/hpkg/PackageInfoAttributeValue.h>
#include <package/hpkg/RepositoryContentHandler.h>
#include <package/hpkg/RepositoryReader.h>
#include <package/hpkg/StandardErrorOutput.h>
#include <package/PackageInfo.h>
#include <package/PackageInfoContentHandler.h>
#include <package/RepositoryInfo.h>

#include "package_repo.h"
#include "PackageInfoPrinter.h"


using namespace BPackageKit::BHPKG;
using namespace BPackageKit;

struct RepositoryContentListHandler : BRepositoryContentHandler {
        RepositoryContentListHandler(bool filenames, bool verbose)
                :
                fPrinter(),
                fLevel(0),
                fVerbose(verbose),
                fFilenames(filenames),
                fPackageInfoContentHandler(fPackageInfo, NULL)
        {
        }

        virtual status_t HandlePackage(const char* packageName)
        {
                return B_OK;
        }

        virtual status_t HandlePackageAttribute(
                const BPackageInfoAttributeValue& value)
        {
                if (fFilenames)
                        fPackageInfoContentHandler.HandlePackageAttribute(value);

                if (value.attributeID == B_PACKAGE_INFO_NAME) {
                        if (fVerbose) {
                                printf("package-attributes:\n");
                                fPrinter.PrintName(value.string);
                        } else if (!fFilenames) {
                                printf("\t%s\n", value.string);
                        }
                } else {
                        if (fVerbose && !fPrinter.PrintAttribute(value)) {
                                printf("*** Invalid package attribute section: unexpected "
                                        "package attribute id %d encountered\n", value.attributeID);
                                return B_BAD_DATA;
                        }
                }

                return B_OK;
        }

        virtual status_t HandlePackageDone(const char* packageName)
        {
                if (fFilenames) {
                        printf("%s%s\n", fVerbose ? "filename: " : "\t",
                                fPackageInfo.CanonicalFileName().String());
                        fPackageInfo.Clear();
                }
                return B_OK;
        }

        virtual status_t HandleRepositoryInfo(const BRepositoryInfo& repositoryInfo)
        {
                printf("repository-info:\n");
                printf("\tname: %s\n", repositoryInfo.Name().String());
                printf("\tsummary: %s\n", repositoryInfo.Summary().String());
                printf("\tbase-url: %s\n", repositoryInfo.BaseURL().String());
                printf("\tidentifier: %s\n", repositoryInfo.Identifier().String());
                printf("\tvendor: %s\n", repositoryInfo.Vendor().String());
                printf("\tpriority: %u\n", repositoryInfo.Priority());
                printf("\tarchitecture: %s\n",
                        BPackageInfo::kArchitectureNames[repositoryInfo.Architecture()]);
                const BStringList licenseNames = repositoryInfo.LicenseNames();
                if (!licenseNames.IsEmpty()) {
                        printf("\tlicenses:\n");
                        for (int i = 0; i < licenseNames.CountStrings(); ++i)
                                printf("\t\t%s\n", licenseNames.StringAt(i).String());
                }
                printf("packages:\n");

                return B_OK;
        }

        virtual void HandleErrorOccurred()
        {
        }

private:
        static void _PrintPackageVersion(const BPackageVersionData& version)
        {
                printf("%s", BPackageVersion(version).ToString().String());
        }

private:
        PackageInfoPrinter      fPrinter;
        int                                     fLevel;
        bool                            fVerbose;

        bool                            fFilenames;
        BPackageInfoContentHandler fPackageInfoContentHandler;
        BPackageInfo            fPackageInfo;
};


int
command_list(int argc, const char* const* argv)
{
        bool verbose = false, filenames = false;

        while (true) {
                static struct option sLongOptions[] = {
                        { "help", no_argument, 0, 'h' },
                        { "filenames", no_argument, 0, 'f' },
                        { "verbose", no_argument, 0, 'v' },
                        { 0, 0, 0, 0 }
                };

                opterr = 0; // don't print errors
                int c = getopt_long(argc, (char**)argv, "+hfv", sLongOptions, NULL);
                if (c == -1)
                        break;

                switch (c) {
                        case 'h':
                                print_usage_and_exit(false);
                                break;

                        case 'f':
                                filenames = true;
                                break;

                        case 'v':
                                verbose = true;
                                break;

                        default:
                                print_usage_and_exit(true);
                                break;
                }
        }

        // One argument should remain -- the repository file name.
        if (optind + 1 != argc)
                print_usage_and_exit(true);

        const char* repositoryFileName = argv[optind++];

        // open repository
        BStandardErrorOutput errorOutput;
        BRepositoryReader repositoryReader(&errorOutput);
        status_t error = repositoryReader.Init(repositoryFileName);
        if (error != B_OK)
                return 1;

        // list
        RepositoryContentListHandler handler(filenames, verbose);
        error = repositoryReader.ParseContent(&handler);
        if (error != B_OK)
                return 1;

        return 0;
}