/*
 * Copyright (c) 2007, Novell Inc.
 *
 * This program is licensed under the BSD license, read LICENSE.BSD
 * for further information
 */

/*
 * rpmdb2solv
 * 
 * Reads rpm database (and evtl. more, like product metadata) to build
 * a .solv file of 'installed' solvables.
 * Writes .solv to stdout
 * 
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifdef ENABLE_RPMDB_LIBRPM
#include <rpm/rpmmacro.h>
#endif


#include "pool.h"
#include "repo.h"
#include "repo_rpmdb.h"
#ifdef ENABLE_PUBKEY
#include "repo_pubkey.h"
#endif
#include "repo_products.h"
#include "repo_solv.h"
#include "common_write.h"
#ifdef ENABLE_APPDATA
#include "repo_appdata.h"
#endif
#ifdef SUSE
#include "repo_autopattern.h"
#endif


static void
usage(int status)
{
  fprintf(stderr, "\nUsage:\n"
	  "rpmdb2solv [-P] [-C] [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
	  " -n : No packages, do not read rpmdb, useful to only parse products\n"
	  " -p <productsdir> : Scan <productsdir> for .prod files, representing installed products\n"
	  " -r <root> : Prefix rpmdb path and <productsdir> with <root>\n"
	  " -o <solv> : Write .solv to file instead of stdout\n"
          " -P : print percentage done\n"
          " -C : include the changelog\n"
	 );
  exit(status);
}


int
main(int argc, char **argv)
{
  FILE *reffp = 0;
  Pool *pool = pool_create();
  Repo *repo;
  Repodata *data;
  int c, percent = 0;
  int nopacks = 0;
  int add_changelog = 0;
  const char *root = 0;
  const char *dbpath = 0;
  const char *refname = 0;
#ifdef ENABLE_SUSEREPO
  char *proddir = 0;
#endif
  char *outfile = 0;
#ifdef ENABLE_PUBKEY
  int pubkeys = 0;
#endif
#ifdef ENABLE_APPDATA
  int add_appdata = 0;
#endif
#ifdef SUSE
  int add_auto = 0;
#endif

  /*
   * parse arguments
   */
  
  while ((c = getopt(argc, argv, "ACD:PhnkxXr:p:o:")) >= 0)
    switch (c)
      {
      case 'h':
	  usage(0);
	break;
      case 'r':
        root = optarg;
        break;
      case 'D':
        dbpath = optarg;
        break;
      case 'n':
	nopacks = 1;
	break;
      case 'P':
	percent = 1;
	break;
      case 'p':
#ifdef ENABLE_SUSEREPO
	proddir = optarg;
#endif
	break;
      case 'x':
        break;	/* extrapool no longer supported */
      case 'X':
#ifdef SUSE
	add_auto = 1;
#endif
	break;
      case 'A':
#ifdef ENABLE_APPDATA
	add_appdata = 1;
#endif
	break;
      case 'o':
        outfile = optarg;
        break;
#ifdef ENABLE_PUBKEY
      case 'k':
        nopacks = 1;
        pubkeys = 1;
        break;
#endif
      case 'C':
	add_changelog = 1;
	break;
      default:
	usage(1);
      }
  
  if (outfile && !freopen(outfile, "w", stdout))
    {
      perror(outfile);
      exit(1);
    }
    
  /*
   * optional arg is old version of rpmdb solv file
   * should make this a real option instead
   */
  
  if (optind < argc)
    refname = argv[optind];

  if (refname && !nopacks)
    {
      if ((reffp = fopen(refname, "r")) == NULL)
        perror(refname);
    }

  /*
   * create 'installed' repository
   * add products
   * add rpmdb
   * write .solv
   */

  if (root && *root)
    pool_set_rootdir(pool, root);
#ifdef ENABLE_PUBKEY
  if (dbpath && *dbpath && (!nopacks || pubkeys))
#else
  if (dbpath && *dbpath && !nopacks)
#endif
    {
#ifdef ENABLE_RPMDB_LIBRPM
      char *macro = solv_dupjoin("_dbpath ", dbpath, 0);
      rpmDefineMacro(NULL, macro, 0);
      free(macro);
#else
      fprintf(stderr, "cannot set dbpath without librpm\n");
      exit(1);
#endif
    }

  repo = repo_create(pool, "installed");
  data = repo_add_repodata(repo, 0);

  if (!nopacks)
    {
      int flags = REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE;
      if (percent)
	flags |= RPMDB_REPORT_PROGRESS;
      if (add_changelog)
	flags |= RPM_ADD_WITH_CHANGELOG;
      if (repo_add_rpmdb_reffp(repo, reffp, flags))
	{
	  fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
	  exit(1);
	}
    }
#ifdef ENABLE_PUBKEY
  if (pubkeys)
    {
      if (repo_add_rpmdb_pubkeys(repo, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | ADD_WITH_KEYSIGNATURES))
	{
	  fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
	  exit(1);
	}
    }
#endif

#ifdef ENABLE_SUSEREPO
  if (proddir && *proddir)
    {
      if (root && *root)
	{
	  int rootlen = strlen(root);
	  if (!strncmp(root, proddir, rootlen))
	    {
	      proddir += rootlen;
	      if (*proddir != '/' && proddir[-1] == '/')
		proddir--;
	    }
	}
      if (repo_add_products(repo, proddir, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
	{
	  fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
	  exit(1);
	}
    }
#endif

#ifdef ENABLE_APPDATA
  if (add_appdata)
    {
      repo_add_appdata_dir(repo, "/usr/share/metainfo", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST);
      repo_add_appdata_dir(repo, "/usr/share/appdata", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST);
    }
#endif
  repodata_internalize(data);

  if (reffp)
    fclose(reffp);

#ifdef SUSE
  if (add_auto)
    repo_add_autopattern(repo, ADD_NO_AUTOPRODUCTS);
#endif

  tool_write(repo, stdout);
  pool_free(pool);
  exit(0);
}
