From ef05b4e31e9337c6c25b92ced7a5613444cf865c Mon Sep 17 00:00:00 2001 From: morganamilo Date: Fri, 24 Sep 2021 23:41:56 +0100 Subject: [PATCH] alpm: add note support Add support for adding a note to packages. This is intended to be set to the user to document the reason or motive a package was installed. Notes can be set for a transaction and only the targets of that transaction gain the note. Notes can also be edited for installed packages similarly to how install reason can be set. --- lib/libalpm/add.c | 16 +++++++++++++++- lib/libalpm/alpm.h | 25 +++++++++++++++++++++++++ lib/libalpm/be_local.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/libalpm/db.c | 6 ++++++ lib/libalpm/package.c | 11 +++++++++++ lib/libalpm/package.h | 2 ++ lib/libalpm/trans.c | 17 +++++++++++++++++ lib/libalpm/trans.h | 1 + 8 files changed, 116 insertions(+), 1 deletion(-) diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index f806e5b2..b733a735 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -431,8 +431,22 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, ASSERT(trans != NULL, return -1); + + if(_alpm_db_get_pkgfromcache(db, newpkg->name)) { + oldpkg = newpkg->oldpkg; + } + + /* set note on package only if it was explicitly added to transaction */ + if(trans->note && newpkg->reason == ALPM_PKG_REASON_EXPLICIT) { + STRDUP(newpkg->note, trans->note, + RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + } else if(oldpkg && oldpkg->note) { + STRDUP(newpkg->note,oldpkg->note, + RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + } + + if(oldpkg) { /* see if this is an upgrade. if so, remove the old package first */ - if(_alpm_db_get_pkgfromcache(db, newpkg->name) && (oldpkg = newpkg->oldpkg)) { int cmp = _alpm_pkg_compare_versions(newpkg, oldpkg); if(cmp < 0) { log_msg = "downgrading"; diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 8d8fe243..a97f4c42 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -2429,6 +2429,12 @@ const char *alpm_pkg_get_desc(alpm_pkg_t *pkg); */ const char *alpm_pkg_get_url(alpm_pkg_t *pkg); +/** Returns the package note. + * @param pkg a pointer to package + * @return a reference to an internal string + */ +char *alpm_pkg_get_note(alpm_pkg_t *pkg); + /** Returns the build timestamp of the package. * @param pkg a pointer to package * @return the timestamp of the build time @@ -2607,6 +2613,15 @@ off_t alpm_pkg_download_size(alpm_pkg_t *newpkg); */ int alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason); +/** Set install note 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 edit + * @param note the new install note, null to remove a note + * @return 0 on success, -1 on error (pm_errno is set accordingly) + */ +int alpm_pkg_set_note(alpm_pkg_t *pkg, char *note); + /* End of libalpm_pkg_t accessors */ /** @} */ @@ -2756,6 +2771,16 @@ alpm_list_t *alpm_trans_get_add(alpm_handle_t *handle); */ alpm_list_t *alpm_trans_get_remove(alpm_handle_t *handle); +/** Sets the install note for a transaction + * + * All target packages will gain the note, dependencies will not. + * + * @param handle the context handle + * @note the the note, may not contain new lines + * @return 0 on success, -1 on error (pm_errno is set accordingly) + */ +int alpm_trans_set_note(alpm_handle_t *handle, char *note); + /** Initialize the transaction. * @param handle the context handle * @param flags flags of the transaction (like nodeps, etc; see alpm_transflag_t) diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 3f40d2e9..8b994d6a 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -81,6 +81,12 @@ static const char *_cache_get_url(alpm_pkg_t *pkg) return pkg->url; } +static char *_cache_get_note(alpm_pkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC); + return pkg->note; +} + static alpm_time_t _cache_get_builddate(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC); @@ -330,6 +336,7 @@ static const struct pkg_operations local_pkg_ops = { .get_base = _cache_get_base, .get_desc = _cache_get_desc, .get_url = _cache_get_url, + .get_note = _cache_get_note, .get_builddate = _cache_get_builddate, .get_installdate = _cache_get_installdate, .get_packager = _cache_get_packager, @@ -752,6 +759,8 @@ static int local_db_read(alpm_pkg_t *info, int inforeq) READ_AND_STORE_ALL(info->groups); } else if(strcmp(line, "%URL%") == 0) { READ_AND_STORE(info->url); + } else if(strcmp(line, "%NOTE%") == 0) { + READ_AND_STORE(info->note); } else if(strcmp(line, "%LICENSE%") == 0) { READ_AND_STORE_ALL(info->licenses); } else if(strcmp(line, "%ARCH%") == 0) { @@ -1040,6 +1049,11 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, int inforeq) write_deps(fp, "%CONFLICTS%", info->conflicts); write_deps(fp, "%PROVIDES%", info->provides); + if(info->note) { + fprintf(fp, "%%NOTE%%\n" + "%s\n\n", info->note); + } + fclose(fp); fp = NULL; } @@ -1158,6 +1172,31 @@ int SYMEXPORT alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason) return 0; } +int SYMEXPORT alpm_pkg_set_note(alpm_pkg_t *pkg, char *note) +{ + 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)); + + _alpm_log(pkg->handle, ALPM_LOG_DEBUG, + "setting note for %s: %s\n", pkg->name, note); + LAZY_LOAD(INFRQ_DESC); + FREE(pkg->note); + if(note) { + ASSERT(!strchr(note, '\n'), RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1)); + STRDUP(pkg->note, note, + RET_ERR(pkg->handle, ALPM_ERR_MEMORY, -1)); + } + /* 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 = { .validate = local_db_validate, .populate = local_db_populate, diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index b8d1b157..ab907568 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -405,6 +405,7 @@ int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles, const char *matched = NULL; const char *name = pkg->name; const char *desc = alpm_pkg_get_desc(pkg); + const char *note = alpm_pkg_get_note(pkg); /* check name as regex AND as plain text */ if(name && (regexec(®, name, 0, 0, 0) == 0 || strstr(name, targ))) { @@ -414,6 +415,11 @@ int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles, else if(desc && regexec(®, desc, 0, 0, 0) == 0) { matched = desc; } + /* check note */ + else if(note && regexec(®, note, 0, 0, 0) == 0) { + matched = note; + } + /* TODO: should we be doing this, and should we print something * differently when we do match it since it isn't currently printed? */ if(!matched) { diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index f837f84a..d6076980 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -78,6 +78,7 @@ int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg) static const char *_pkg_get_base(alpm_pkg_t *pkg) { return pkg->base; } static const char *_pkg_get_desc(alpm_pkg_t *pkg) { return pkg->desc; } static const char *_pkg_get_url(alpm_pkg_t *pkg) { return pkg->url; } +static char *_pkg_get_note(alpm_pkg_t *pkg) { return pkg->note; } static alpm_time_t _pkg_get_builddate(alpm_pkg_t *pkg) { return pkg->builddate; } static alpm_time_t _pkg_get_installdate(alpm_pkg_t *pkg) { return pkg->installdate; } static const char *_pkg_get_packager(alpm_pkg_t *pkg) { return pkg->packager; } @@ -142,6 +143,7 @@ const struct pkg_operations default_pkg_ops = { .get_base = _pkg_get_base, .get_desc = _pkg_get_desc, .get_url = _pkg_get_url, + .get_note = _pkg_get_note, .get_builddate = _pkg_get_builddate, .get_installdate = _pkg_get_installdate, .get_packager = _pkg_get_packager, @@ -226,6 +228,13 @@ const char SYMEXPORT *alpm_pkg_get_url(alpm_pkg_t *pkg) return pkg->ops->get_url(pkg); } +char SYMEXPORT *alpm_pkg_get_note(alpm_pkg_t *pkg) +{ + ASSERT(pkg != NULL, return NULL); + pkg->handle->pm_errno = ALPM_ERR_OK; + return pkg->ops->get_note(pkg); +} + alpm_time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return -1); @@ -610,6 +619,7 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) STRDUP(newpkg->version, pkg->version, goto cleanup); STRDUP(newpkg->desc, pkg->desc, goto cleanup); STRDUP(newpkg->url, pkg->url, goto cleanup); + STRDUP(newpkg->note, pkg->note, goto cleanup); newpkg->builddate = pkg->builddate; newpkg->installdate = pkg->installdate; STRDUP(newpkg->packager, pkg->packager, goto cleanup); @@ -683,6 +693,7 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) FREE(pkg->version); FREE(pkg->desc); FREE(pkg->url); + FREE(pkg->note); FREE(pkg->packager); FREE(pkg->md5sum); FREE(pkg->sha256sum); diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index 3332bbb3..f500d72a 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -46,6 +46,7 @@ struct pkg_operations { const char *(*get_base) (alpm_pkg_t *); const char *(*get_desc) (alpm_pkg_t *); const char *(*get_url) (alpm_pkg_t *); + char *(*get_note) (alpm_pkg_t *); alpm_time_t (*get_builddate) (alpm_pkg_t *); alpm_time_t (*get_installdate) (alpm_pkg_t *); const char *(*get_packager) (alpm_pkg_t *); @@ -93,6 +94,7 @@ struct _alpm_pkg_t { char *version; char *desc; char *url; + char *note; char *packager; char *md5sum; char *sha256sum; diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index ae5c72ae..d03b4e74 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -298,6 +298,7 @@ void _alpm_trans_free(alpm_trans_t *trans) alpm_list_free(trans->add); alpm_list_free_inner(trans->remove, (alpm_list_fn_free)_alpm_pkg_free); alpm_list_free(trans->remove); + FREE(trans->note); FREELIST(trans->skip_remove); @@ -450,3 +451,19 @@ alpm_list_t SYMEXPORT *alpm_trans_get_remove(alpm_handle_t *handle) return handle->trans->remove; } + +int SYMEXPORT alpm_trans_set_note(alpm_handle_t *handle, char *note) { + CHECK_HANDLE(handle, return -1); + ASSERT(handle->trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); + ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); + + if(handle->trans->note) { + ASSERT(!strchr(handle->trans->note, '\n'), RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); + free(handle->trans->note); + handle->trans->note = NULL; + } + + STRDUP(handle->trans->note, note, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + return 0; +} + diff --git a/lib/libalpm/trans.h b/lib/libalpm/trans.h index d2ec0223..fe38f054 100644 --- a/lib/libalpm/trans.h +++ b/lib/libalpm/trans.h @@ -39,6 +39,7 @@ typedef enum _alpm_transstate_t { typedef struct _alpm_trans_t { /* bitfield of alpm_transflag_t flags */ int flags; + char *note; alpm_transstate_t state; alpm_list_t *unresolvable; /* list of (alpm_pkg_t *) */ alpm_list_t *add; /* list of (alpm_pkg_t *) */