summaryrefslogblamecommitdiff
path: root/src/ver.c
blob: d41c601b30e462138e9e367c0408d28dee4a04e5 (plain) (tree)
1
2
3
4
5
6
7


                                                       
                                                          

                       
                                                                          








                                                                           
                      
 
                
                                                                              
                             
                         

  
                                                                              









                                                        

                                                      
                                         




                 
                                                                           


              
                           

                         
                                                              
                                                 


                 
                                                                               
 




                                                                 
                                              

                                                      

                 
                      
 
 

                                                               


                                                      


                                           

                                        
                                                                              
                      

                                            
                                                                              
                      


                                        


                                   





                          
                                                                                                            

                              
                          

                                                                
                                      
                      



                                                         

                         


                                                                        
                                 
                                                                        
                                 
                                                                      

                                         

                                                   

                                       
                                                    

                              
         

                                                                          
                                         
                                                                                 
                       



                                                

                                                       











                                                                                        

 
                                                                                      
 
                                                      
                                           
                              
                                

                    
 


                                                
                                                          

                                     
 
                                 
                                              
 


                                                          
                             
                                                                  
                                                          
                                                                      
                 
                              
         
 

                                                                  
                                   
                                                          


                                      


                                                                


         
                   

 
                                          
                                                                              

                                                                               
                                                                               

                                                                                                

  

                                    

                                                                                
                                     



                                               




                           
/* ver.c - Alpine Package Keeper (APK)
 *
 * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
 * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation. See http://www.gnu.org/ for details.
 */

#include <stdio.h>
#include "apk_defines.h"
#include "apk_applet.h"
#include "apk_database.h"
#include "apk_version.h"
#include "apk_print.h"

struct ver_ctx {
	int (*action)(struct apk_database *db, struct apk_string_array *args);
	const char *limchars;
	int all_tags : 1;
};

static int ver_indexes(struct apk_database *db, struct apk_string_array *args)
{
	struct apk_repository *repo;
	int i;

	for (i = 0; i < db->num_repos; i++) {
		repo = &db->repos[i];

		if (APK_BLOB_IS_NULL(repo->description))
			continue;

		printf(BLOB_FMT " [%s]\n",
		       BLOB_PRINTF(repo->description),
		       db->repos[i].url);
	}

	return 0;
}

static int ver_test(struct apk_database *db, struct apk_string_array *args)
{
	int r;

	if (args->num != 2)
		return 1;

	r = apk_version_compare(args->item[0], args->item[1]);
	printf("%s\n", apk_version_op_string(r));
	return 0;
}

static int ver_validate(struct apk_database *db, struct apk_string_array *args)
{
	char **parg;
	int errors = 0;

	foreach_array_item(parg, args) {
		if (!apk_version_validate(APK_BLOB_STR(*parg))) {
			if (apk_verbosity > 0)
				printf("%s\n", *parg);
			errors++;
		}
	}
	return errors;
}

static int ver_parse(void *ctx, struct apk_db_options *dbopts,
		     int opt, int optindex, const char *optarg)
{
	struct ver_ctx *ictx = (struct ver_ctx *) ctx;
	switch (opt) {
	case 'I':
		ictx->action = ver_indexes;
		break;
	case 't':
		ictx->action = ver_test;
		dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS;
		break;
	case 'c':
		ictx->action = ver_validate;
		dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS;
		break;
	case 'l':
		ictx->limchars = optarg;
		break;
	case 'a':
		ictx->all_tags = 1;
		break;
	default:
		return -1;
	}
	return 0;
}

static void ver_print_package_status(struct ver_ctx *ictx, struct apk_database *db, struct apk_package *pkg)
{
	struct apk_name *name;
	char pkgname[256];
	const char *opstr;
	apk_blob_t *latest = apk_blob_atomize(APK_BLOB_STR(""));
	unsigned int latest_repos = 0;
	int i, r = -1;
	unsigned short tag, allowed_repos;

	tag = pkg->ipkg ? pkg->ipkg->repository_tag : 0;
	allowed_repos = db->repo_tags[tag].allowed_repos;

	name = pkg->name;
	for (i = 0; i < name->providers->num; i++) {
		struct apk_package *pkg0 = name->providers->item[i].pkg;
		if (pkg0->name != name || pkg0->repos == 0)
			continue;
		if (!(ictx->all_tags  || (pkg0->repos & allowed_repos)))
			continue;
		r = apk_version_compare_blob(*pkg0->version, *latest);
		switch (r) {
		case APK_VERSION_GREATER:
			latest = pkg0->version;
			latest_repos = pkg0->repos;
			break;
		case APK_VERSION_EQUAL:
			latest_repos |= pkg0->repos;
			break;
		}
	}
	r = latest->len ? apk_version_compare_blob(*pkg->version, *latest)
			: APK_VERSION_UNKNOWN;
	opstr = apk_version_op_string(r);
	if ((ictx->limchars != NULL) && (strchr(ictx->limchars, *opstr) == NULL))
		return;
	if (apk_verbosity <= 0) {
		printf("%s\n", pkg->name->name);
		return;
	}
	snprintf(pkgname, sizeof(pkgname), PKG_VER_FMT,
		 PKG_VER_PRINTF(pkg));
	printf("%-40s%s " BLOB_FMT, pkgname, opstr, BLOB_PRINTF(*latest));
	if (!(latest_repos & db->repo_tags[APK_DEFAULT_REPOSITORY_TAG].allowed_repos)) {
		for (i = 1; i < db->num_repo_tags; i++) {
			if (!(latest_repos & db->repo_tags[i].allowed_repos))
				continue;
			if (!(ictx->all_tags || i == tag))
				continue;
			printf(" @" BLOB_FMT,
			       BLOB_PRINTF(*db->repo_tags[i].name));
		}
	}
	printf("\n");
}

static int ver_main(void *ctx, struct apk_database *db, struct apk_string_array *args)
{
	struct ver_ctx *ictx = (struct ver_ctx *) ctx;
	struct apk_installed_package *ipkg;
	struct apk_name *name;
	struct apk_package *pkg;
	char **parg;
	int ret = 0;

	if (ictx->limchars) {
		if (strlen(ictx->limchars) == 0)
			ictx->limchars = NULL;
	} else if (args->num == 0 && apk_verbosity == 1) {
		ictx->limchars = "<";
	}

	if (ictx->action != NULL)
		return ictx->action(db, args);

	if (apk_verbosity > 0)
		printf("%-42sAvailable:\n", "Installed:");

	if (args->num == 0) {
		list_for_each_entry(ipkg, &db->installed.packages,
				    installed_pkgs_list) {
			ver_print_package_status(ictx, db, ipkg->pkg);
		}
		goto ver_exit;
	}

	foreach_array_item(parg, args) {
		name = apk_db_query_name(db, APK_BLOB_STR(*parg));
		if (name == NULL) {
			apk_error("Not found: %s", *parg);
			ret = 1;
			goto ver_exit;
		}
		pkg = apk_pkg_get_installed(name);
		if (pkg != NULL)
			ver_print_package_status(ictx, db, pkg);
	}

ver_exit:
	return ret;
}

static struct apk_option ver_options[] = {
	{ 'I', "indexes",	"Print description and versions of indexes" },
	{ 't', "test",		"Compare two given versions" },
	{ 'c', "check", 	"Check if the given version string is valid" },
	{ 'a', "all",		"Consider packages from all repository tags" },
	{ 'l', "limit",		"Limit output to packages with status matching one of LIMCHARS",
	  required_argument, "LIMCHARS" },
};

static struct apk_applet apk_ver = {
	.name = "version",
	.help = "Compare package versions (in installed database vs. available)"
		" or do tests on version strings given on command line.",
	.open_flags = APK_OPENF_READ,
	.context_size = sizeof(struct ver_ctx),
	.num_options = ARRAY_SIZE(ver_options),
	.options = ver_options,
	.parse = ver_parse,
	.main = ver_main,
};

APK_DEFINE_APPLET(apk_ver);