Merge branch 'master' into 'master'
Add user notes via xdata field See merge request pacman/pacman!206
This commit is contained in:
commit
764ad3c402
27 changed files with 679 additions and 11 deletions
|
@ -1438,6 +1438,17 @@ alpm_list_t *alpm_db_get_groupcache(alpm_db_t *db);
|
||||||
int alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
int alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
||||||
alpm_list_t **ret);
|
alpm_list_t **ret);
|
||||||
|
|
||||||
|
/** Searches a database with regular expressions.
|
||||||
|
* @param db pointer to the package database to search in
|
||||||
|
* @param needles a list of regular expressions to search for
|
||||||
|
* @param notes a list of regular expressions to search in extended data field
|
||||||
|
* @param ret pointer to list for storing packages matching all
|
||||||
|
* regular expressions - must point to an empty (NULL) alpm_list_t *.
|
||||||
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
||||||
|
*/
|
||||||
|
int alpm_db_search_usernote(alpm_db_t *db, const alpm_list_t *needles,
|
||||||
|
const alpm_list_t *notes, alpm_list_t **ret);
|
||||||
|
|
||||||
/** The usage level of a database. */
|
/** The usage level of a database. */
|
||||||
typedef enum _alpm_db_usage_t {
|
typedef enum _alpm_db_usage_t {
|
||||||
/** Enable refreshes for this database */
|
/** Enable refreshes for this database */
|
||||||
|
@ -2677,6 +2688,44 @@ int alpm_pkg_get_validation(alpm_pkg_t *pkg);
|
||||||
*/
|
*/
|
||||||
alpm_list_t *alpm_pkg_get_xdata(alpm_pkg_t *pkg);
|
alpm_list_t *alpm_pkg_get_xdata(alpm_pkg_t *pkg);
|
||||||
|
|
||||||
|
/** Gets user data prefix for extended data field keys
|
||||||
|
* @return a const reference to a key prefix
|
||||||
|
*/
|
||||||
|
const char *alpm_get_userdata_prefix(void);
|
||||||
|
|
||||||
|
/** Gets a list of user notes for a package. Caller is responsible
|
||||||
|
* for freeing the returned list
|
||||||
|
* @param pkg a pointer to package
|
||||||
|
* @return a reference to a list of alpm_pkg_xdata_t objects
|
||||||
|
*/
|
||||||
|
alpm_list_t *alpm_pkg_get_user_notes(alpm_pkg_t *pkg);
|
||||||
|
|
||||||
|
/** Updates user notes with passed list. Notes names will be prepended
|
||||||
|
* internally with the user prefix
|
||||||
|
* @param pkg a pointer to package
|
||||||
|
* @param notes a reference to a list of alpm_pkg_xdata_t objects
|
||||||
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
||||||
|
*/
|
||||||
|
int alpm_pkg_user_notes_update(alpm_pkg_t *pkg, const alpm_list_t *notes);
|
||||||
|
|
||||||
|
/** Deletes user notes matching passed keys list
|
||||||
|
* @param pkg a pointer to package
|
||||||
|
* @param keys a reference to a list of char*
|
||||||
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
||||||
|
*/
|
||||||
|
int alpm_pkg_user_notes_delete(alpm_pkg_t *pkg, const alpm_list_t *keys);
|
||||||
|
|
||||||
|
/** Parse string into an extended data structure
|
||||||
|
* @param string a pointer to string
|
||||||
|
* @return a reference to xdata on success, NULL on failure
|
||||||
|
*/
|
||||||
|
alpm_pkg_xdata_t *alpm_pkg_parse_xdata(const char *string);
|
||||||
|
|
||||||
|
/** Free an extended data structure.
|
||||||
|
* @param xdata a reference to an xdata to free
|
||||||
|
*/
|
||||||
|
void alpm_pkg_xdata_free(alpm_pkg_xdata_t *xdata);
|
||||||
|
|
||||||
/** Returns whether the package has an install scriptlet.
|
/** Returns whether the package has an install scriptlet.
|
||||||
* @return 0 if FALSE, TRUE otherwise
|
* @return 0 if FALSE, TRUE otherwise
|
||||||
*/
|
*/
|
||||||
|
@ -2698,6 +2747,15 @@ off_t alpm_pkg_download_size(alpm_pkg_t *newpkg);
|
||||||
*/
|
*/
|
||||||
int alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason);
|
int alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason);
|
||||||
|
|
||||||
|
/** Set user notes for a package in the local database.
|
||||||
|
* The provided package object must be from the local database or this method
|
||||||
|
* will fail. The write to the local database is performed immediately.
|
||||||
|
* @param pkg the package to update
|
||||||
|
* @param notes list of \link alpm_pkg_xdata_t \endlink structures
|
||||||
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
||||||
|
*/
|
||||||
|
int alpm_pkg_set_user_notes(alpm_pkg_t *pkg, const alpm_list_t *notes);
|
||||||
|
|
||||||
|
|
||||||
/* End of libalpm_pkg_t accessors */
|
/* End of libalpm_pkg_t accessors */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -1205,6 +1205,38 @@ int SYMEXPORT alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SYMEXPORT alpm_pkg_set_user_notes(alpm_pkg_t *pkg, const alpm_list_t *notes)
|
||||||
|
{
|
||||||
|
ASSERT(pkg != NULL, return -1);
|
||||||
|
ASSERT(pkg->origin == ALPM_PKG_FROM_LOCALDB,
|
||||||
|
RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1));
|
||||||
|
ASSERT(pkg->origin_data.db == pkg->handle->db_local,
|
||||||
|
RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1));
|
||||||
|
pkg->handle->pm_errno = ALPM_ERR_OK;
|
||||||
|
const char *prefix = alpm_get_userdata_prefix();
|
||||||
|
|
||||||
|
alpm_list_t *pkg_xdata = alpm_pkg_get_xdata(pkg);
|
||||||
|
alpm_list_t *new_pkg_xdata = NULL;
|
||||||
|
for(alpm_list_t *i = pkg_xdata; i; i = alpm_list_next(i)) {
|
||||||
|
alpm_pkg_xdata_t *xdata = i->data;
|
||||||
|
if(strncmp(xdata->name, prefix, strlen(prefix)) != 0) {
|
||||||
|
alpm_pkg_xdata_t *tmp = _alpm_pkg_xdata_dup(xdata);
|
||||||
|
alpm_list_append(&new_pkg_xdata, tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkg->xdata = new_pkg_xdata;
|
||||||
|
alpm_list_free_inner(pkg_xdata, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(pkg_xdata);
|
||||||
|
alpm_pkg_user_notes_update(pkg, notes);
|
||||||
|
|
||||||
|
/* write DESC */
|
||||||
|
if(_alpm_local_db_write(pkg->handle->db_local, pkg, INFRQ_DESC)) {
|
||||||
|
RET_ERR(pkg->handle, ALPM_ERR_DB_WRITE, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct db_operations local_db_ops = {
|
static const struct db_operations local_db_ops = {
|
||||||
.validate = local_db_validate,
|
.validate = local_db_validate,
|
||||||
.populate = local_db_populate,
|
.populate = local_db_populate,
|
||||||
|
|
|
@ -350,7 +350,17 @@ int SYMEXPORT alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
||||||
RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
|
RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
|
||||||
db->handle->pm_errno = ALPM_ERR_OK;
|
db->handle->pm_errno = ALPM_ERR_OK;
|
||||||
|
|
||||||
return _alpm_db_search(db, needles, ret);
|
return _alpm_db_search(db, needles, NULL, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SYMEXPORT alpm_db_search_usernote(alpm_db_t *db, const alpm_list_t *needles,
|
||||||
|
const alpm_list_t *notes, alpm_list_t **ret)
|
||||||
|
{
|
||||||
|
ASSERT(db != NULL && ret != NULL && *ret == NULL,
|
||||||
|
RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
|
||||||
|
db->handle->pm_errno = ALPM_ERR_OK;
|
||||||
|
|
||||||
|
return _alpm_db_search(db, needles, notes, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SYMEXPORT alpm_db_set_usage(alpm_db_t *db, int usage)
|
int SYMEXPORT alpm_db_set_usage(alpm_db_t *db, int usage)
|
||||||
|
@ -440,7 +450,7 @@ int _alpm_db_cmp(const void *d1, const void *d2)
|
||||||
}
|
}
|
||||||
|
|
||||||
int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
||||||
alpm_list_t **ret)
|
const alpm_list_t *notes, alpm_list_t **ret)
|
||||||
{
|
{
|
||||||
const alpm_list_t *i, *j, *k;
|
const alpm_list_t *i, *j, *k;
|
||||||
|
|
||||||
|
@ -451,6 +461,60 @@ int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
||||||
/* copy the pkgcache- we will free the list var after each needle */
|
/* copy the pkgcache- we will free the list var after each needle */
|
||||||
alpm_list_t *list = alpm_list_copy(_alpm_db_get_pkgcache(db));
|
alpm_list_t *list = alpm_list_copy(_alpm_db_get_pkgcache(db));
|
||||||
|
|
||||||
|
/* search in extended data field */
|
||||||
|
for(i = notes; i; i = i->next) {
|
||||||
|
char *targ;
|
||||||
|
regex_t reg;
|
||||||
|
|
||||||
|
if(i->data == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*ret = NULL;
|
||||||
|
targ = i->data;
|
||||||
|
_alpm_log(db->handle, ALPM_LOG_DEBUG,
|
||||||
|
"searching for '%s' in extended data field\n", targ);
|
||||||
|
|
||||||
|
if(regcomp(®, targ, REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE) != 0) {
|
||||||
|
db->handle->pm_errno = ALPM_ERR_INVALID_REGEX;
|
||||||
|
alpm_list_free(list);
|
||||||
|
alpm_list_free(*ret);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j = list; j; j = j->next) {
|
||||||
|
alpm_pkg_t *pkg = j->data;
|
||||||
|
alpm_list_t *pkg_notes = alpm_pkg_get_user_notes(pkg);
|
||||||
|
for(k = pkg_notes; k; k = k->next) {
|
||||||
|
alpm_pkg_xdata_t *pkg_xdata = k->data;
|
||||||
|
/* pack xdata into flat cstring for searching */
|
||||||
|
char *xdata_str = NULL;
|
||||||
|
int maxlen = strlen(pkg_xdata->name) + strlen(pkg_xdata->value) + 2;
|
||||||
|
CALLOC(xdata_str, 1, maxlen,
|
||||||
|
db->handle->pm_errno = ALPM_ERR_MEMORY;
|
||||||
|
alpm_list_free(list);
|
||||||
|
alpm_list_free(*ret);
|
||||||
|
return -1
|
||||||
|
);
|
||||||
|
snprintf(xdata_str, maxlen, "%s=%s", pkg_xdata->name, pkg_xdata->value);
|
||||||
|
if(regexec(®, xdata_str, 0, 0, 0) == 0 || strstr(xdata_str, targ)) {
|
||||||
|
_alpm_log(db->handle, ALPM_LOG_DEBUG,
|
||||||
|
"search in notes for '%s' matched on package '%s'\n",
|
||||||
|
targ, pkg->name);
|
||||||
|
*ret = alpm_list_add(*ret, pkg);
|
||||||
|
}
|
||||||
|
free(xdata_str);
|
||||||
|
}
|
||||||
|
alpm_list_free_inner(pkg_notes, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(pkg_notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the existing search list, and use the returned list for the
|
||||||
|
* next needle. This allows for AND-based package searching. */
|
||||||
|
alpm_list_free(list);
|
||||||
|
list = *ret;
|
||||||
|
regfree(®);
|
||||||
|
}
|
||||||
|
|
||||||
for(i = needles; i; i = i->next) {
|
for(i = needles; i; i = i->next) {
|
||||||
char *targ;
|
char *targ;
|
||||||
regex_t reg;
|
regex_t reg;
|
||||||
|
|
|
@ -89,7 +89,7 @@ void _alpm_db_free(alpm_db_t *db);
|
||||||
const char *_alpm_db_path(alpm_db_t *db);
|
const char *_alpm_db_path(alpm_db_t *db);
|
||||||
int _alpm_db_cmp(const void *d1, const void *d2);
|
int _alpm_db_cmp(const void *d1, const void *d2);
|
||||||
int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
|
||||||
alpm_list_t **ret);
|
const alpm_list_t *xdata, alpm_list_t **ret);
|
||||||
alpm_db_t *_alpm_db_register_local(alpm_handle_t *handle);
|
alpm_db_t *_alpm_db_register_local(alpm_handle_t *handle);
|
||||||
alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
|
alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
|
||||||
int level);
|
int level);
|
||||||
|
|
|
@ -35,6 +35,12 @@
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "deps.h"
|
#include "deps.h"
|
||||||
|
|
||||||
|
static const char *XDATA_USERDATA_PREFIX = "user:";
|
||||||
|
|
||||||
|
const char SYMEXPORT *alpm_get_userdata_prefix(void) {
|
||||||
|
return XDATA_USERDATA_PREFIX;
|
||||||
|
}
|
||||||
|
|
||||||
int SYMEXPORT alpm_pkg_free(alpm_pkg_t *pkg)
|
int SYMEXPORT alpm_pkg_free(alpm_pkg_t *pkg)
|
||||||
{
|
{
|
||||||
ASSERT(pkg != NULL, return -1);
|
ASSERT(pkg != NULL, return -1);
|
||||||
|
@ -47,6 +53,109 @@ int SYMEXPORT alpm_pkg_free(alpm_pkg_t *pkg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alpm_pkg_xdata_t SYMEXPORT *alpm_pkg_parse_xdata(const char *string) {
|
||||||
|
ASSERT(string != NULL, return NULL);
|
||||||
|
|
||||||
|
return _alpm_pkg_parse_xdata(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
alpm_list_t SYMEXPORT *alpm_pkg_get_user_notes(alpm_pkg_t *pkg) {
|
||||||
|
ASSERT(pkg != NULL, return NULL);
|
||||||
|
pkg->handle->pm_errno = ALPM_ERR_OK;
|
||||||
|
alpm_list_t *user_notes = NULL;
|
||||||
|
const char *prefix = alpm_get_userdata_prefix();
|
||||||
|
for(alpm_list_t *i = alpm_pkg_get_xdata(pkg); i; i = alpm_list_next(i)) {
|
||||||
|
alpm_pkg_xdata_t *xdata = i->data;
|
||||||
|
if(strncmp(xdata->name, prefix, strlen(prefix)) == 0) {
|
||||||
|
alpm_pkg_xdata_t *user_note = _alpm_pkg_user_note_dup(xdata, NULL);
|
||||||
|
memmove(user_note->name,
|
||||||
|
user_note->name + strlen(prefix),
|
||||||
|
strlen(user_note->name) - strlen(prefix) + 1);
|
||||||
|
user_notes = alpm_list_add(user_notes, user_note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user_notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SYMEXPORT alpm_pkg_user_notes_update(alpm_pkg_t *pkg, const alpm_list_t *notes) {
|
||||||
|
ASSERT(pkg != NULL, return -1);
|
||||||
|
pkg->handle->pm_errno = ALPM_ERR_OK;
|
||||||
|
if(notes == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char *prefix = alpm_get_userdata_prefix();
|
||||||
|
|
||||||
|
alpm_list_t *pkg_xdata_lst = alpm_pkg_get_xdata(pkg);
|
||||||
|
for(const alpm_list_t *i = notes; i; i = alpm_list_next(i)) {
|
||||||
|
alpm_pkg_xdata_t *xdata = i->data;
|
||||||
|
int found_existing_key = 0;
|
||||||
|
for(alpm_list_t *j = pkg_xdata_lst; j; j = alpm_list_next(j)) {
|
||||||
|
alpm_pkg_xdata_t *pkg_xdata = j->data;
|
||||||
|
if(strncmp(pkg_xdata->name, prefix, strlen(prefix)) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(strcmp(pkg_xdata->name + strlen(prefix), xdata->name) == 0) {
|
||||||
|
found_existing_key = 1;
|
||||||
|
alpm_pkg_xdata_t *new_xdata = _alpm_pkg_user_note_dup(xdata, prefix);
|
||||||
|
if(new_xdata == NULL) {
|
||||||
|
pkg->handle->pm_errno = ALPM_ERR_MEMORY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
j->data = new_xdata;
|
||||||
|
_alpm_pkg_xdata_free(pkg_xdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found_existing_key) {
|
||||||
|
alpm_pkg_xdata_t *new_xdata = _alpm_pkg_user_note_dup(xdata, prefix);
|
||||||
|
if(new_xdata == NULL) {
|
||||||
|
pkg->handle->pm_errno = ALPM_ERR_MEMORY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pkg_xdata_lst = alpm_list_add(pkg_xdata_lst, new_xdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkg->xdata = pkg_xdata_lst;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SYMEXPORT alpm_pkg_user_notes_delete(alpm_pkg_t *pkg, const alpm_list_t *keys) {
|
||||||
|
ASSERT(pkg != NULL, return -1);
|
||||||
|
pkg->handle->pm_errno = ALPM_ERR_OK;
|
||||||
|
if(keys == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char *prefix = alpm_get_userdata_prefix();
|
||||||
|
|
||||||
|
alpm_list_t *pkg_xdata_lst = alpm_pkg_get_xdata(pkg);
|
||||||
|
alpm_list_t *new_pkg_xdata_lst = NULL;
|
||||||
|
for(alpm_list_t *j = pkg_xdata_lst; j; j = alpm_list_next(j)) {
|
||||||
|
alpm_pkg_xdata_t *pkg_xdata = j->data;
|
||||||
|
int skip_key = 0;
|
||||||
|
for(const alpm_list_t *i = keys; i; i = alpm_list_next(i)) {
|
||||||
|
const char *key = i->data;
|
||||||
|
if(strncmp(pkg_xdata->name, prefix, strlen(prefix)) == 0
|
||||||
|
&& strcmp(pkg_xdata->name + strlen(prefix), key) == 0) {
|
||||||
|
skip_key = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!skip_key) {
|
||||||
|
printf("dup %s\n", pkg_xdata->name);
|
||||||
|
alpm_pkg_xdata_t *tmp = _alpm_pkg_xdata_dup(pkg_xdata);
|
||||||
|
alpm_list_append(&new_pkg_xdata_lst, tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkg->xdata = new_pkg_xdata_lst;
|
||||||
|
alpm_list_free_inner(pkg_xdata_lst, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(pkg_xdata_lst);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SYMEXPORT alpm_pkg_xdata_free(alpm_pkg_xdata_t *xdata) {
|
||||||
|
ASSERT(xdata != NULL, return);
|
||||||
|
_alpm_pkg_xdata_free(xdata);
|
||||||
|
}
|
||||||
|
|
||||||
int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg)
|
int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg)
|
||||||
{
|
{
|
||||||
char *fpath;
|
char *fpath;
|
||||||
|
@ -702,6 +811,36 @@ alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string)
|
||||||
return pd;
|
return pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alpm_pkg_xdata_t *_alpm_pkg_xdata_dup(const alpm_pkg_xdata_t *xdata) {
|
||||||
|
alpm_pkg_xdata_t *pd;
|
||||||
|
|
||||||
|
CALLOC(pd, 1, sizeof(alpm_pkg_xdata_t), return NULL);
|
||||||
|
STRDUP(pd->name, xdata->name, FREE(pd); return NULL);
|
||||||
|
STRDUP(pd->value, xdata->value, FREE(pd->name); FREE(pd); return NULL);
|
||||||
|
|
||||||
|
return pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
alpm_pkg_xdata_t *_alpm_pkg_user_note_dup(const alpm_pkg_xdata_t *xdata, const char *prefix) {
|
||||||
|
ASSERT(xdata != NULL, return NULL);
|
||||||
|
|
||||||
|
alpm_pkg_xdata_t *new_xdata;
|
||||||
|
CALLOC(new_xdata, 1, sizeof(alpm_pkg_xdata_t), return NULL);
|
||||||
|
int key_alloc_size = strlen(xdata->name) + 1;
|
||||||
|
if(prefix) {
|
||||||
|
key_alloc_size += strlen(prefix);
|
||||||
|
}
|
||||||
|
CALLOC(new_xdata->name, 1, key_alloc_size, FREE(new_xdata); return NULL);
|
||||||
|
if(prefix) {
|
||||||
|
sprintf(new_xdata->name, "%s%s", prefix, xdata->name);
|
||||||
|
} else {
|
||||||
|
sprintf(new_xdata->name, "%s", xdata->name);
|
||||||
|
}
|
||||||
|
STRDUP(new_xdata->value, xdata->value, FREE(new_xdata->name); FREE(new_xdata);
|
||||||
|
return NULL);
|
||||||
|
return new_xdata;
|
||||||
|
}
|
||||||
|
|
||||||
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd)
|
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd)
|
||||||
{
|
{
|
||||||
if(pd) {
|
if(pd) {
|
||||||
|
|
|
@ -163,6 +163,9 @@ int _alpm_pkg_cmp(const void *p1, const void *p2);
|
||||||
int _alpm_pkg_compare_versions(alpm_pkg_t *local_pkg, alpm_pkg_t *pkg);
|
int _alpm_pkg_compare_versions(alpm_pkg_t *local_pkg, alpm_pkg_t *pkg);
|
||||||
|
|
||||||
alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string);
|
alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string);
|
||||||
|
alpm_pkg_xdata_t *_alpm_pkg_xdata_dup(const alpm_pkg_xdata_t *xdata);
|
||||||
|
alpm_pkg_xdata_t *_alpm_pkg_user_note_dup(const alpm_pkg_xdata_t *xdata, const char *prefix);
|
||||||
|
void _alpm_pkg_set_xdata(alpm_pkg_t *pkg, alpm_list_t *xdata_lst);
|
||||||
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd);
|
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd);
|
||||||
|
|
||||||
int _alpm_pkg_check_meta(alpm_pkg_t *pkg);
|
int _alpm_pkg_check_meta(alpm_pkg_t *pkg);
|
||||||
|
|
|
@ -1175,6 +1175,21 @@ static int load_packages(alpm_handle_t *handle, alpm_list_t **data,
|
||||||
|
|
||||||
PROGRESS(handle, ALPM_PROGRESS_LOAD_START, "", percent,
|
PROGRESS(handle, ALPM_PROGRESS_LOAD_START, "", percent,
|
||||||
total, current);
|
total, current);
|
||||||
|
|
||||||
|
/* check localdb for user notes and update new package */
|
||||||
|
alpm_db_t *localdb = alpm_get_localdb(handle);
|
||||||
|
alpm_pkg_t *localpkg = alpm_db_get_pkg(localdb, spkg->name);
|
||||||
|
if(localpkg != NULL) {
|
||||||
|
alpm_list_t *new_notes = alpm_pkg_get_user_notes(spkg);
|
||||||
|
alpm_list_t *old_notes = alpm_pkg_get_user_notes(localpkg);
|
||||||
|
alpm_pkg_user_notes_update(spkg, old_notes);
|
||||||
|
alpm_pkg_user_notes_update(spkg, new_notes);
|
||||||
|
alpm_list_free_inner(old_notes, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(old_notes);
|
||||||
|
alpm_list_free_inner(new_notes, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(new_notes);
|
||||||
|
}
|
||||||
|
|
||||||
if(spkg->origin == ALPM_PKG_FROM_FILE) {
|
if(spkg->origin == ALPM_PKG_FROM_FILE) {
|
||||||
continue; /* pkg_load() has been already called, this package is valid */
|
continue; /* pkg_load() has been already called, this package is valid */
|
||||||
}
|
}
|
||||||
|
@ -1209,6 +1224,11 @@ static int load_packages(alpm_handle_t *handle, alpm_list_t **data,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
free(filepath);
|
free(filepath);
|
||||||
|
/* copy user notes */
|
||||||
|
alpm_list_t *user_notes = alpm_pkg_get_user_notes(spkg);
|
||||||
|
alpm_pkg_user_notes_update(pkgfile, user_notes);
|
||||||
|
alpm_list_free_inner(user_notes, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(user_notes);
|
||||||
/* copy over the install reason */
|
/* copy over the install reason */
|
||||||
pkgfile->reason = spkg->reason;
|
pkgfile->reason = spkg->reason;
|
||||||
/* copy over validation method */
|
/* copy over validation method */
|
||||||
|
|
|
@ -150,6 +150,9 @@ int config_free(config_t *oldconfig)
|
||||||
FREELIST(oldconfig->noupgrade);
|
FREELIST(oldconfig->noupgrade);
|
||||||
FREELIST(oldconfig->noextract);
|
FREELIST(oldconfig->noextract);
|
||||||
FREELIST(oldconfig->overwrite_files);
|
FREELIST(oldconfig->overwrite_files);
|
||||||
|
FREELIST(oldconfig->user_note);
|
||||||
|
FREELIST(oldconfig->user_note_extra);
|
||||||
|
FREELIST(oldconfig->user_note_delete);
|
||||||
free(oldconfig->configfile);
|
free(oldconfig->configfile);
|
||||||
free(oldconfig->sysroot);
|
free(oldconfig->sysroot);
|
||||||
free(oldconfig->rootdir);
|
free(oldconfig->rootdir);
|
||||||
|
|
|
@ -86,6 +86,7 @@ typedef struct __config_t {
|
||||||
unsigned short op_q_upgrade;
|
unsigned short op_q_upgrade;
|
||||||
unsigned short op_q_check;
|
unsigned short op_q_check;
|
||||||
unsigned short op_q_locality;
|
unsigned short op_q_locality;
|
||||||
|
unsigned short op_q_usernote_delete;
|
||||||
|
|
||||||
unsigned short op_s_clean;
|
unsigned short op_s_clean;
|
||||||
unsigned short op_s_downloadonly;
|
unsigned short op_s_downloadonly;
|
||||||
|
@ -127,6 +128,9 @@ typedef struct __config_t {
|
||||||
alpm_list_t *noupgrade;
|
alpm_list_t *noupgrade;
|
||||||
alpm_list_t *noextract;
|
alpm_list_t *noextract;
|
||||||
alpm_list_t *overwrite_files;
|
alpm_list_t *overwrite_files;
|
||||||
|
alpm_list_t *user_note;
|
||||||
|
alpm_list_t *user_note_extra;
|
||||||
|
alpm_list_t *user_note_delete;
|
||||||
char *xfercommand;
|
char *xfercommand;
|
||||||
char **xfercommand_argv;
|
char **xfercommand_argv;
|
||||||
size_t xfercommand_argc;
|
size_t xfercommand_argc;
|
||||||
|
@ -214,7 +218,10 @@ enum {
|
||||||
OP_REFRESH,
|
OP_REFRESH,
|
||||||
OP_ASSUMEINSTALLED,
|
OP_ASSUMEINSTALLED,
|
||||||
OP_DISABLEDLTIMEOUT,
|
OP_DISABLEDLTIMEOUT,
|
||||||
OP_DISABLESANDBOX
|
OP_DISABLESANDBOX,
|
||||||
|
OP_USERNOTE,
|
||||||
|
OP_USERNOTE_EXTRA,
|
||||||
|
OP_USERNOTE_DELETE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* clean method */
|
/* clean method */
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
/* pacman */
|
/* pacman */
|
||||||
#include "pacman.h"
|
#include "pacman.h"
|
||||||
|
#include "package.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -91,6 +92,55 @@ static int change_install_reason(alpm_list_t *targets)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modify the 'local' package database.
|
||||||
|
*
|
||||||
|
* @param targets a list of packages (as strings) to modify
|
||||||
|
* @param add list of alpm_pkg_xdata_t to add
|
||||||
|
* @param remove list of char* keys to remove
|
||||||
|
*
|
||||||
|
* @return 0 on success, 1 on failure
|
||||||
|
*/
|
||||||
|
static int change_user_notes(alpm_list_t *targets, const alpm_list_t *add, const alpm_list_t *delete) {
|
||||||
|
const alpm_list_t *i;
|
||||||
|
alpm_db_t *db_local;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if(targets == NULL) {
|
||||||
|
pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock database */
|
||||||
|
if(trans_init(0, 0) == -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
db_local = alpm_get_localdb(config->handle);
|
||||||
|
for(i = targets; i; i = alpm_list_next(i)) {
|
||||||
|
char *pkgname = i->data;
|
||||||
|
alpm_pkg_t *pkg = alpm_db_get_pkg(db_local, pkgname);
|
||||||
|
if(pkg == NULL) {
|
||||||
|
pm_printf(ALPM_LOG_ERROR, _("could not get local package %s (%s)\n"),
|
||||||
|
pkgname, alpm_strerror(alpm_errno(config->handle)));
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
alpm_pkg_user_notes_delete(pkg, delete);
|
||||||
|
alpm_pkg_user_notes_update(pkg, add);
|
||||||
|
alpm_list_t *pkg_notes = alpm_pkg_get_user_notes(pkg);
|
||||||
|
alpm_pkg_set_user_notes(pkg, pkg_notes);
|
||||||
|
alpm_list_free_inner(pkg_notes, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(pkg_notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock database */
|
||||||
|
if(trans_release() == -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_db_missing_deps(alpm_list_t *pkglist)
|
static int check_db_missing_deps(alpm_list_t *pkglist)
|
||||||
{
|
{
|
||||||
alpm_list_t *data, *i;
|
alpm_list_t *data, *i;
|
||||||
|
@ -301,5 +351,31 @@ int pacman_database(alpm_list_t *targets)
|
||||||
ret = change_install_reason(targets);
|
ret = change_install_reason(targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config->user_note || config->user_note_extra || config->user_note_delete) {
|
||||||
|
alpm_list_t *i, *usernote_add = NULL;
|
||||||
|
for(i = config->user_note; i; i = alpm_list_next(i)) {
|
||||||
|
const char *arg = i->data;
|
||||||
|
const char *key = get_default_user_note_key();
|
||||||
|
char *full_note = calloc(1, strlen(key) + 1 + strlen(arg) + 1);
|
||||||
|
sprintf(full_note, "%s=%s", key, arg);
|
||||||
|
alpm_pkg_xdata_t *user_note = alpm_pkg_parse_xdata(full_note);
|
||||||
|
free(full_note);
|
||||||
|
usernote_add = alpm_list_add(usernote_add, user_note);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = config->user_note_extra; i; i = alpm_list_next(i)) {
|
||||||
|
const char *arg = i->data;
|
||||||
|
alpm_pkg_xdata_t *user_note = alpm_pkg_parse_xdata(arg);
|
||||||
|
if(user_note == NULL) {
|
||||||
|
pm_printf(ALPM_LOG_ERROR, "failed to parse user note '%s'\n", arg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
usernote_add = alpm_list_add(usernote_add, user_note);
|
||||||
|
}
|
||||||
|
change_user_notes(targets, usernote_add, config->user_note_delete);
|
||||||
|
alpm_list_free_inner(usernote_add, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(usernote_add);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,12 @@ enum {
|
||||||
|
|
||||||
static char titles[_T_MAX][TITLE_MAXLEN * sizeof(wchar_t)];
|
static char titles[_T_MAX][TITLE_MAXLEN * sizeof(wchar_t)];
|
||||||
|
|
||||||
|
static const char *XDATA_DEFAULT_USER_KEY = "note";
|
||||||
|
|
||||||
|
const char *get_default_user_note_key(void) {
|
||||||
|
return XDATA_DEFAULT_USER_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
/** Build the `titles` array of localized titles and pad them with spaces so
|
/** Build the `titles` array of localized titles and pad them with spaces so
|
||||||
* that they align with the longest title. Storage for strings is stack
|
* that they align with the longest title. Storage for strings is stack
|
||||||
* allocated and naively truncated to TITLE_MAXLEN characters.
|
* allocated and naively truncated to TITLE_MAXLEN characters.
|
||||||
|
@ -351,6 +357,21 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra)
|
||||||
dump_pkg_backups(pkg, cols);
|
dump_pkg_backups(pkg, cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alpm_list_t *user_notes = alpm_pkg_get_user_notes(pkg);
|
||||||
|
if(user_notes) {
|
||||||
|
alpm_list_t *text = NULL;
|
||||||
|
for(alpm_list_t *i = user_notes; i; i = alpm_list_next(i)) {
|
||||||
|
alpm_pkg_xdata_t *note = i->data;
|
||||||
|
char *formatted = NULL;
|
||||||
|
pm_asprintf(&formatted, "%s=%s", note->name, note->value);
|
||||||
|
text = alpm_list_add(text, formatted);
|
||||||
|
}
|
||||||
|
list_display_linebreak("User Notes :", text, cols);
|
||||||
|
FREELIST(text);
|
||||||
|
}
|
||||||
|
alpm_list_free_inner(user_notes, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(user_notes);
|
||||||
|
|
||||||
if(extra) {
|
if(extra) {
|
||||||
alpm_list_t *text = NULL, *pdata = alpm_pkg_get_xdata(pkg);
|
alpm_list_t *text = NULL, *pdata = alpm_pkg_get_xdata(pkg);
|
||||||
while(pdata) {
|
while(pdata) {
|
||||||
|
@ -539,7 +560,7 @@ int dump_pkg_search(alpm_db_t *db, alpm_list_t *targets, int show_status)
|
||||||
{
|
{
|
||||||
int freelist = 0;
|
int freelist = 0;
|
||||||
alpm_db_t *db_local;
|
alpm_db_t *db_local;
|
||||||
alpm_list_t *i, *searchlist = NULL;
|
alpm_list_t *i, *j, *searchlist = NULL;
|
||||||
unsigned short cols;
|
unsigned short cols;
|
||||||
const colstr_t *colstr = &config->colstr;
|
const colstr_t *colstr = &config->colstr;
|
||||||
|
|
||||||
|
@ -548,9 +569,15 @@ int dump_pkg_search(alpm_db_t *db, alpm_list_t *targets, int show_status)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we have a targets list, search for packages matching it */
|
/* if we have a targets list, search for packages matching it */
|
||||||
if(targets) {
|
if(targets || config->user_note) {
|
||||||
if(alpm_db_search(db, targets, &searchlist) != 0) {
|
if(config->user_note) {
|
||||||
return -1;
|
if(alpm_db_search_usernote(db, targets, config->user_note, &searchlist) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if(alpm_db_search(db, targets, &searchlist) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
freelist = 1;
|
freelist = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -580,6 +607,20 @@ int dump_pkg_search(alpm_db_t *db, alpm_list_t *targets, int show_status)
|
||||||
/* we need a newline and initial indent first */
|
/* we need a newline and initial indent first */
|
||||||
fputs("\n ", stdout);
|
fputs("\n ", stdout);
|
||||||
indentprint(alpm_pkg_get_desc(pkg), 4, cols);
|
indentprint(alpm_pkg_get_desc(pkg), 4, cols);
|
||||||
|
/* if we're searching for user note, print package notes */
|
||||||
|
if(config->user_note) {
|
||||||
|
alpm_list_t *pkg_notes = alpm_pkg_get_user_notes(pkg);
|
||||||
|
for(j = pkg_notes; j; j = alpm_list_next(j)) {
|
||||||
|
alpm_pkg_xdata_t *xdata = j->data;
|
||||||
|
char *user_note = calloc(1, strlen(xdata->name) + 1 + strlen(xdata->value) + 1);
|
||||||
|
fputs("\n ", stdout);
|
||||||
|
sprintf(user_note, "%s=%s", xdata->name, xdata->value);
|
||||||
|
indentprint(user_note, 4, cols);
|
||||||
|
free(user_note);
|
||||||
|
}
|
||||||
|
alpm_list_free_inner(pkg_notes, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(pkg_notes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,5 +31,6 @@ void dump_pkg_changelog(alpm_pkg_t *pkg);
|
||||||
void print_installed(alpm_db_t *db_local, alpm_pkg_t *pkg);
|
void print_installed(alpm_db_t *db_local, alpm_pkg_t *pkg);
|
||||||
void print_groups(alpm_pkg_t *pkg);
|
void print_groups(alpm_pkg_t *pkg);
|
||||||
int dump_pkg_search(alpm_db_t *db, alpm_list_t *targets, int show_status);
|
int dump_pkg_search(alpm_db_t *db, alpm_list_t *targets, int show_status);
|
||||||
|
const char *get_default_user_note_key(void);
|
||||||
|
|
||||||
#endif /* PM_PACKAGE_H */
|
#endif /* PM_PACKAGE_H */
|
||||||
|
|
|
@ -147,6 +147,9 @@ static void usage(int op, const char * const myname)
|
||||||
addlist(_(" -p, --file <package> query a package file instead of the database\n"));
|
addlist(_(" -p, --file <package> query a package file instead of the database\n"));
|
||||||
addlist(_(" -q, --quiet show less information for query and search\n"));
|
addlist(_(" -q, --quiet show less information for query and search\n"));
|
||||||
addlist(_(" -s, --search <regex> search locally-installed packages for matching strings\n"));
|
addlist(_(" -s, --search <regex> search locally-installed packages for matching strings\n"));
|
||||||
|
addlist(_(" --note-search <regex>\n"
|
||||||
|
" search locally-installed packages for matching strings\n"
|
||||||
|
" inside user-added notes\n"));
|
||||||
addlist(_(" -t, --unrequired list packages not (optionally) required by any\n"
|
addlist(_(" -t, --unrequired list packages not (optionally) required by any\n"
|
||||||
" package (-tt to ignore optdepends) [filter]\n"));
|
" package (-tt to ignore optdepends) [filter]\n"));
|
||||||
addlist(_(" -u, --upgrades list outdated packages [filter]\n"));
|
addlist(_(" -u, --upgrades list outdated packages [filter]\n"));
|
||||||
|
@ -171,6 +174,11 @@ static void usage(int op, const char * const myname)
|
||||||
addlist(_(" --asexplicit mark packages as explicitly installed\n"));
|
addlist(_(" --asexplicit mark packages as explicitly installed\n"));
|
||||||
addlist(_(" -k, --check test local database for validity (-kk for sync databases)\n"));
|
addlist(_(" -k, --check test local database for validity (-kk for sync databases)\n"));
|
||||||
addlist(_(" -q, --quiet suppress output of success messages\n"));
|
addlist(_(" -q, --quiet suppress output of success messages\n"));
|
||||||
|
addlist(_(" --note <note> set user note for a package (default key: 'note')\n"));
|
||||||
|
addlist(_(" --note-extra <key>=<value>\n"
|
||||||
|
" set extra user note for a package\n"));
|
||||||
|
addlist(_(" --delete-note <key>\n"
|
||||||
|
" delete user note from package\n"));
|
||||||
} else if(op == PM_OP_DEPTEST) {
|
} else if(op == PM_OP_DEPTEST) {
|
||||||
printf("%s: %s {-T --deptest} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg);
|
printf("%s: %s {-T --deptest} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg);
|
||||||
printf("%s:\n", str_opt);
|
printf("%s:\n", str_opt);
|
||||||
|
@ -193,6 +201,9 @@ static void usage(int op, const char * const myname)
|
||||||
" overwrite conflicting files (can be used more than once)\n"));
|
" overwrite conflicting files (can be used more than once)\n"));
|
||||||
addlist(_(" --asdeps install packages as non-explicitly installed\n"));
|
addlist(_(" --asdeps install packages as non-explicitly installed\n"));
|
||||||
addlist(_(" --asexplicit install packages as explicitly installed\n"));
|
addlist(_(" --asexplicit install packages as explicitly installed\n"));
|
||||||
|
addlist(_(" --note <note> set user note for a package (default key: 'note')\n"));
|
||||||
|
addlist(_(" --note-extra <key>=<value>\n"
|
||||||
|
" set extra user note for a package\n"));
|
||||||
addlist(_(" --ignore <pkg> ignore a package upgrade (can be used more than once)\n"));
|
addlist(_(" --ignore <pkg> ignore a package upgrade (can be used more than once)\n"));
|
||||||
addlist(_(" --ignoregroup <grp>\n"
|
addlist(_(" --ignoregroup <grp>\n"
|
||||||
" ignore a group upgrade (can be used more than once)\n"));
|
" ignore a group upgrade (can be used more than once)\n"));
|
||||||
|
@ -521,6 +532,16 @@ static int parsearg_database(int opt)
|
||||||
case OP_QUIET:
|
case OP_QUIET:
|
||||||
case 'q':
|
case 'q':
|
||||||
config->quiet = 1;
|
config->quiet = 1;
|
||||||
|
break;
|
||||||
|
case OP_USERNOTE:
|
||||||
|
parsearg_util_addlist(&(config->user_note));
|
||||||
|
break;
|
||||||
|
case OP_USERNOTE_EXTRA:
|
||||||
|
parsearg_util_addlist(&(config->user_note_extra));
|
||||||
|
break;
|
||||||
|
case OP_USERNOTE_DELETE:
|
||||||
|
parsearg_util_addlist(&(config->user_note_delete));
|
||||||
|
break;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -597,6 +618,10 @@ static int parsearg_query(int opt)
|
||||||
case 's':
|
case 's':
|
||||||
config->op_q_search = 1;
|
config->op_q_search = 1;
|
||||||
break;
|
break;
|
||||||
|
case OP_USERNOTE:
|
||||||
|
config->op_q_search = 1;
|
||||||
|
parsearg_util_addlist(&(config->user_note));
|
||||||
|
break;
|
||||||
case OP_UNREQUIRED:
|
case OP_UNREQUIRED:
|
||||||
case 't':
|
case 't':
|
||||||
(config->op_q_unrequired)++;
|
(config->op_q_unrequired)++;
|
||||||
|
@ -764,6 +789,12 @@ static int parsearg_upgrade(int opt)
|
||||||
case OP_NEEDED:
|
case OP_NEEDED:
|
||||||
config->flags |= ALPM_TRANS_FLAG_NEEDED;
|
config->flags |= ALPM_TRANS_FLAG_NEEDED;
|
||||||
break;
|
break;
|
||||||
|
case OP_USERNOTE:
|
||||||
|
parsearg_util_addlist(&(config->user_note));
|
||||||
|
break;
|
||||||
|
case OP_USERNOTE_EXTRA:
|
||||||
|
parsearg_util_addlist(&(config->user_note_extra));
|
||||||
|
break;
|
||||||
case OP_IGNORE:
|
case OP_IGNORE:
|
||||||
parsearg_util_addlist(&(config->ignorepkg));
|
parsearg_util_addlist(&(config->ignorepkg));
|
||||||
break;
|
break;
|
||||||
|
@ -975,6 +1006,10 @@ static int parseargs(int argc, char *argv[])
|
||||||
{"ignoregroup", required_argument, 0, OP_IGNOREGROUP},
|
{"ignoregroup", required_argument, 0, OP_IGNOREGROUP},
|
||||||
{"needed", no_argument, 0, OP_NEEDED},
|
{"needed", no_argument, 0, OP_NEEDED},
|
||||||
{"asexplicit", no_argument, 0, OP_ASEXPLICIT},
|
{"asexplicit", no_argument, 0, OP_ASEXPLICIT},
|
||||||
|
{"note", required_argument, 0, OP_USERNOTE},
|
||||||
|
{"note-extra", required_argument, 0, OP_USERNOTE_EXTRA},
|
||||||
|
{"note-search", required_argument, 0, OP_USERNOTE},
|
||||||
|
{"delete-note", required_argument, 0, OP_USERNOTE_DELETE},
|
||||||
{"arch", required_argument, 0, OP_ARCH},
|
{"arch", required_argument, 0, OP_ARCH},
|
||||||
{"print-format", required_argument, 0, OP_PRINTFORMAT},
|
{"print-format", required_argument, 0, OP_PRINTFORMAT},
|
||||||
{"gpgdir", required_argument, 0, OP_GPGDIR},
|
{"gpgdir", required_argument, 0, OP_GPGDIR},
|
||||||
|
|
|
@ -761,8 +761,57 @@ static void print_broken_dep(alpm_depmissing_t *miss)
|
||||||
|
|
||||||
int sync_prepare_execute(void)
|
int sync_prepare_execute(void)
|
||||||
{
|
{
|
||||||
alpm_list_t *i, *packages, *data = NULL;
|
alpm_list_t *i, *packages, *data = NULL, *notes_lst = NULL;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
const char *default_key = get_default_user_note_key();
|
||||||
|
|
||||||
|
/* Step 1.1: set user-added extended data fields */
|
||||||
|
for(i = config->user_note; i; i = alpm_list_next(i)) {
|
||||||
|
const char *xdata_arg = i->data;
|
||||||
|
/* extra 1 byte for '=' */
|
||||||
|
char *xdata_full_arg = calloc(1,
|
||||||
|
strlen(xdata_arg) + strlen(default_key) + 2
|
||||||
|
);
|
||||||
|
if(xdata_full_arg == NULL) {
|
||||||
|
pm_printf(ALPM_LOG_ERROR, _("memory allocation error\n"));
|
||||||
|
retval = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
sprintf(xdata_full_arg, "%s=%s", default_key, xdata_arg);
|
||||||
|
alpm_pkg_xdata_t *xdata = alpm_pkg_parse_xdata(xdata_full_arg);
|
||||||
|
if(xdata == NULL) {
|
||||||
|
pm_printf(ALPM_LOG_ERROR, _("failed to parse extended data field: %s\n"), xdata_arg);
|
||||||
|
free(xdata_full_arg);
|
||||||
|
retval = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
free(xdata_full_arg);
|
||||||
|
alpm_list_append(¬es_lst, xdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = config->user_note_extra; i; i = alpm_list_next(i)) {
|
||||||
|
const char *xdata_arg = i->data;
|
||||||
|
alpm_pkg_xdata_t *xdata = alpm_pkg_parse_xdata(xdata_arg);
|
||||||
|
if(xdata == NULL) {
|
||||||
|
pm_printf(ALPM_LOG_ERROR, _("failed to parse extended data field: %s\n"), xdata_arg);
|
||||||
|
retval = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
alpm_list_append(¬es_lst, xdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(notes_lst != NULL) {
|
||||||
|
packages = alpm_trans_get_add(config->handle);
|
||||||
|
for(i = packages; i; i = alpm_list_next(i)) {
|
||||||
|
alpm_pkg_t *pkg = i->data;
|
||||||
|
if(alpm_pkg_user_notes_update(pkg, notes_lst) != 0) {
|
||||||
|
pm_printf(ALPM_LOG_ERROR, _("failed to update user notes for package %s\n"),
|
||||||
|
alpm_pkg_get_name(pkg));
|
||||||
|
retval = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Step 2: "compute" the transaction based on targets and flags */
|
/* Step 2: "compute" the transaction based on targets and flags */
|
||||||
if(alpm_trans_prepare(config->handle, &data) == -1) {
|
if(alpm_trans_prepare(config->handle, &data) == -1) {
|
||||||
|
@ -889,6 +938,9 @@ int sync_prepare_execute(void)
|
||||||
|
|
||||||
/* Step 4: release transaction resources */
|
/* Step 4: release transaction resources */
|
||||||
cleanup:
|
cleanup:
|
||||||
|
alpm_list_free_inner(notes_lst, (alpm_list_fn_free)alpm_pkg_xdata_free);
|
||||||
|
alpm_list_free(notes_lst);
|
||||||
|
|
||||||
alpm_list_free(data);
|
alpm_list_free(data);
|
||||||
if(trans_release() == -1) {
|
if(trans_release() == -1) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
|
|
|
@ -341,6 +341,15 @@ pacman_tests = [
|
||||||
'tests/upgrade-download-404.py',
|
'tests/upgrade-download-404.py',
|
||||||
'tests/upgrade-download-pkg-and-sig-with-filename.py',
|
'tests/upgrade-download-pkg-and-sig-with-filename.py',
|
||||||
'tests/upgrade-download-with-xfercommand.py',
|
'tests/upgrade-download-with-xfercommand.py',
|
||||||
|
'tests/usernote-01-change-localdb.py',
|
||||||
|
'tests/usernote-02-set-localdb.py',
|
||||||
|
'tests/usernote-03-set-sync.py',
|
||||||
|
'tests/usernote-04-prs-sync-reinstall.py',
|
||||||
|
'tests/usernote-05-prs-sync-upgrade.py',
|
||||||
|
'tests/usernote-06-prs-upgrade-from-file.py',
|
||||||
|
'tests/usernote-07-prs-non-user-xdata.py',
|
||||||
|
'tests/usernote-08-query-note-search.py',
|
||||||
|
'tests/usernote-09-query-note-info.py',
|
||||||
]
|
]
|
||||||
|
|
||||||
xfail_tests = {
|
xfail_tests = {
|
||||||
|
|
|
@ -157,6 +157,8 @@ class pmdb(object):
|
||||||
pkg.conflicts = _getsection(fd)
|
pkg.conflicts = _getsection(fd)
|
||||||
elif line == "%PROVIDES%":
|
elif line == "%PROVIDES%":
|
||||||
pkg.provides = _getsection(fd)
|
pkg.provides = _getsection(fd)
|
||||||
|
elif line == "%XDATA%":
|
||||||
|
pkg.xdata = _getsection(fd)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
# files
|
# files
|
||||||
|
@ -203,6 +205,7 @@ class pmdb(object):
|
||||||
make_section(data, "OPTDEPENDS", pkg.optdepends)
|
make_section(data, "OPTDEPENDS", pkg.optdepends)
|
||||||
make_section(data, "CONFLICTS", pkg.conflicts)
|
make_section(data, "CONFLICTS", pkg.conflicts)
|
||||||
make_section(data, "PROVIDES", pkg.provides)
|
make_section(data, "PROVIDES", pkg.provides)
|
||||||
|
make_section(data, "XDATA", pkg.xdata)
|
||||||
make_section(data, "URL", pkg.url)
|
make_section(data, "URL", pkg.url)
|
||||||
if self.is_local:
|
if self.is_local:
|
||||||
make_section(data, "INSTALLDATE", pkg.installdate)
|
make_section(data, "INSTALLDATE", pkg.installdate)
|
||||||
|
|
|
@ -64,6 +64,7 @@ class pmpkg(object):
|
||||||
}
|
}
|
||||||
self.path = None
|
self.path = None
|
||||||
self.finalized = False
|
self.finalized = False
|
||||||
|
self.xdata = []
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
s = ["%s" % self.fullname()]
|
s = ["%s" % self.fullname()]
|
||||||
|
@ -137,6 +138,8 @@ class pmpkg(object):
|
||||||
data.append("provides = %s" % i)
|
data.append("provides = %s" % i)
|
||||||
for i in self.backup:
|
for i in self.backup:
|
||||||
data.append("backup = %s" % i)
|
data.append("backup = %s" % i)
|
||||||
|
for i in self.xdata:
|
||||||
|
data.append("xdata = %s" % i)
|
||||||
archive_files.append((".PKGINFO", "\n".join(data)))
|
archive_files.append((".PKGINFO", "\n".join(data)))
|
||||||
|
|
||||||
# .INSTALL
|
# .INSTALL
|
||||||
|
|
|
@ -33,7 +33,7 @@ class pmrule(object):
|
||||||
return self.rule
|
return self.rule
|
||||||
|
|
||||||
def snapshots_needed(self):
|
def snapshots_needed(self):
|
||||||
(testname, args) = self.rule.split("=")
|
(testname, args) = self.rule.split("=", 1)
|
||||||
if testname == "FILE_MODIFIED" or testname == "!FILE_MODIFIED":
|
if testname == "FILE_MODIFIED" or testname == "!FILE_MODIFIED":
|
||||||
return [args]
|
return [args]
|
||||||
return []
|
return []
|
||||||
|
@ -43,7 +43,7 @@ class pmrule(object):
|
||||||
"""
|
"""
|
||||||
success = 1
|
success = 1
|
||||||
|
|
||||||
[testname, args] = self.rule.split("=")
|
[testname, args] = self.rule.split("=", 1)
|
||||||
if testname[0] == "!":
|
if testname[0] == "!":
|
||||||
self.false = 1
|
self.false = 1
|
||||||
testname = testname[1:]
|
testname = testname[1:]
|
||||||
|
@ -108,6 +108,9 @@ class pmrule(object):
|
||||||
if f.startswith(value + "\t"):
|
if f.startswith(value + "\t"):
|
||||||
success = 1
|
success = 1
|
||||||
break;
|
break;
|
||||||
|
elif case == "XDATA":
|
||||||
|
if not value in newpkg.xdata:
|
||||||
|
success = 0
|
||||||
else:
|
else:
|
||||||
tap.diag("PKG rule '%s' not found" % case)
|
tap.diag("PKG rule '%s' not found" % case)
|
||||||
success = -1
|
success = -1
|
||||||
|
|
13
test/pacman/tests/usernote-01-change-localdb.py
Normal file
13
test/pacman/tests/usernote-01-change-localdb.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
self.description = "Change localdb notes"
|
||||||
|
|
||||||
|
sp = pmpkg("pkg")
|
||||||
|
sp.xdata = ["user:note=user note", 'user:foo=bar']
|
||||||
|
self.addpkg2db("local", sp);
|
||||||
|
|
||||||
|
self.args = "-D --delete-note note --delete-note foo --note-extra bar=foo pkg"
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PKG_EXIST=pkg")
|
||||||
|
self.addrule("!PKG_XDATA=pkg|user:note=user note")
|
||||||
|
self.addrule("!PKG_XDATA=pkg|user:foo=bar")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:bar=foo")
|
11
test/pacman/tests/usernote-02-set-localdb.py
Normal file
11
test/pacman/tests/usernote-02-set-localdb.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
self.description = "Set note in localdb"
|
||||||
|
|
||||||
|
sp = pmpkg("pkg")
|
||||||
|
self.addpkg2db("local", sp);
|
||||||
|
|
||||||
|
self.args = "-D --note 'user note' --note-extra foo=bar pkg"
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PKG_EXIST=pkg")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:note=user note")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:foo=bar")
|
11
test/pacman/tests/usernote-03-set-sync.py
Normal file
11
test/pacman/tests/usernote-03-set-sync.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
self.description = "Set note on install"
|
||||||
|
|
||||||
|
sp = pmpkg("pkg")
|
||||||
|
self.addpkg2db("sync", sp);
|
||||||
|
|
||||||
|
self.args = "-S --note 'user note' --note-extra foo=bar pkg"
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PKG_EXIST=pkg")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:note=user note")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:foo=bar")
|
14
test/pacman/tests/usernote-04-prs-sync-reinstall.py
Normal file
14
test/pacman/tests/usernote-04-prs-sync-reinstall.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
self.description = "Reinstall sync package, with user note in localdb"
|
||||||
|
|
||||||
|
sp = pmpkg("pkg")
|
||||||
|
self.addpkg2db("sync", sp);
|
||||||
|
sp = pmpkg("pkg")
|
||||||
|
sp.xdata = ['user:note=user note']
|
||||||
|
self.addpkg2db("local", sp);
|
||||||
|
|
||||||
|
self.args = "-S --note-extra foo=bar pkg"
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PKG_EXIST=pkg")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:note=user note")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:foo=bar")
|
14
test/pacman/tests/usernote-05-prs-sync-upgrade.py
Normal file
14
test/pacman/tests/usernote-05-prs-sync-upgrade.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
self.description = "Upgrade sync package, with user note in localdb"
|
||||||
|
|
||||||
|
sp = pmpkg("pkg", "1.1-1")
|
||||||
|
self.addpkg2db("sync", sp);
|
||||||
|
sp = pmpkg("pkg", "1.0-1")
|
||||||
|
sp.xdata = ['user:note=user note']
|
||||||
|
self.addpkg2db("local", sp);
|
||||||
|
|
||||||
|
self.args = "-Su --note-extra foo=bar pkg"
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PKG_EXIST=pkg")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:note=user note")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:foo=bar")
|
15
test/pacman/tests/usernote-06-prs-upgrade-from-file.py
Normal file
15
test/pacman/tests/usernote-06-prs-upgrade-from-file.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
self.description = "Upgrade from file, with user note in localdb"
|
||||||
|
|
||||||
|
lp = pmpkg("pkg")
|
||||||
|
lp.xdata=['user:note=user note']
|
||||||
|
self.addpkg2db("local", lp)
|
||||||
|
|
||||||
|
p = pmpkg("pkg", "1.0-2")
|
||||||
|
self.addpkg(p)
|
||||||
|
|
||||||
|
self.args = "-U --note-extra foo=bar %s" % p.filename()
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PKG_VERSION=pkg|1.0-2")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:note=user note")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:foo=bar")
|
18
test/pacman/tests/usernote-07-prs-non-user-xdata.py
Normal file
18
test/pacman/tests/usernote-07-prs-non-user-xdata.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
self.description = "Upgrade from file, with non-user xdata changed"
|
||||||
|
|
||||||
|
lp = pmpkg("pkg")
|
||||||
|
lp.xdata=['user:note=user note', 'pkgtype=pkg']
|
||||||
|
self.addpkg2db("local", lp)
|
||||||
|
|
||||||
|
p = pmpkg("pkg", "1.0-2")
|
||||||
|
p.xdata=['newfield=test']
|
||||||
|
self.addpkg(p)
|
||||||
|
|
||||||
|
self.args = "-U --note-extra foo=bar %s" % p.filename()
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PKG_VERSION=pkg|1.0-2")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:note=user note")
|
||||||
|
self.addrule("PKG_XDATA=pkg|user:foo=bar")
|
||||||
|
self.addrule("PKG_XDATA=pkg|newfield=test")
|
||||||
|
self.addrule("!PKG_XDATA=pkg|pkgtype=pkg")
|
12
test/pacman/tests/usernote-08-query-note-search.py
Normal file
12
test/pacman/tests/usernote-08-query-note-search.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
self.description = "Search for user note"
|
||||||
|
|
||||||
|
sp = pmpkg("searchpkg")
|
||||||
|
sp.xdata = ['user:foo=bar']
|
||||||
|
self.addpkg2db("local", sp);
|
||||||
|
|
||||||
|
self.args = "-Q --note-search bar"
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PACMAN_OUTPUT=searchpkg")
|
||||||
|
self.addrule("PACMAN_OUTPUT=foo=bar")
|
||||||
|
|
11
test/pacman/tests/usernote-09-query-note-info.py
Normal file
11
test/pacman/tests/usernote-09-query-note-info.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
self.description = "Print user notes in pkg info query"
|
||||||
|
|
||||||
|
sp = pmpkg("pkg")
|
||||||
|
sp.xdata = ['user:foo=bar']
|
||||||
|
self.addpkg2db("local", sp);
|
||||||
|
|
||||||
|
self.args = "-Qi pkg"
|
||||||
|
|
||||||
|
self.addrule("PACMAN_RETCODE=0")
|
||||||
|
self.addrule("PACMAN_OUTPUT=foo=bar")
|
||||||
|
|
Loading…
Add table
Reference in a new issue