...
 
Commits (11)
......@@ -4,7 +4,7 @@
-include config.mk
PACKAGE := apk-tools
VERSION := 2.8.1
VERSION := 2.8.2
##
# Default directories
......
......@@ -764,25 +764,44 @@ ouch:
}
static struct url *
http_get_proxy(struct url * url, const char *flags)
http_make_proxy_url(const char *env1, const char *env2)
{
struct url *purl;
char *p;
p = getenv(env1);
if (!p)
p = getenv(env2);
if (!p || !*p)
return NULL;
purl = fetchParseURL(p);
if (!purl)
return NULL;
if (!*purl->scheme)
strcpy(purl->scheme, SCHEME_HTTP);
if (!purl->port)
purl->port = fetch_default_proxy_port(purl->scheme);
if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0)
return purl;
fetchFreeURL(purl);
return NULL;
}
static struct url *
http_get_proxy(struct url * url, const char *flags)
{
if (flags != NULL && strchr(flags, 'd') != NULL)
return (NULL);
if (fetch_no_proxy_match(url->host))
return (NULL);
if (((p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) &&
*p && (purl = fetchParseURL(p))) {
if (!*purl->scheme)
strcpy(purl->scheme, SCHEME_HTTP);
if (!purl->port)
purl->port = fetch_default_proxy_port(purl->scheme);
if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0)
return (purl);
fetchFreeURL(purl);
}
if (strcasecmp(url->scheme, SCHEME_HTTPS) == 0)
return http_make_proxy_url("HTTPS_PROXY", "https_proxy");
if (strcasecmp(url->scheme, SCHEME_HTTP) == 0)
return http_make_proxy_url("HTTP_PROXY", "http_proxy");
return (NULL);
}
......@@ -817,7 +836,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
{
conn_t *conn;
struct url *url, *new;
int chunked, direct, if_modified_since, need_auth, noredirect;
int chunked, direct, if_modified_since, need_auth, noredirect, nocache;
int keep_alive, verbose, cached;
int e, i, n, val;
off_t offset, clength, length, size;
......@@ -829,6 +848,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
direct = CHECK_FLAG('d');
noredirect = CHECK_FLAG('A');
nocache = CHECK_FLAG('C');
verbose = CHECK_FLAG('v');
if_modified_since = CHECK_FLAG('i');
keep_alive = 0;
......@@ -898,6 +918,8 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
op, url->doc);
}
if (nocache)
http_cmd(conn, "Cache-Control: no-cache\r\n");
if (if_modified_since && url->last_modified > 0)
set_if_modified_since(conn, url->last_modified);
......
......@@ -60,7 +60,7 @@ static const struct apk_option_group optgroup_applet = {
static int non_repository_check(struct apk_database *db)
{
if (apk_flags & APK_FORCE)
if (apk_force & APK_FORCE_NON_REPOSITORY)
return 0;
if (apk_db_cache_active(db))
return 0;
......@@ -69,8 +69,8 @@ static int non_repository_check(struct apk_database *db)
apk_error("You tried to add a non-repository package to system, "
"but it would be lost on next reboot. Enable package caching "
"(apk cache --help) or use --force if you know what you are "
"doing.");
"(apk cache --help) or use --force-non-repository "
"if you know what you are doing.");
return 1;
}
......
......@@ -95,7 +95,27 @@ static int option_parse_global(void *ctx, struct apk_db_options *dbopts, int opt
version();
return -ESHUTDOWN;
case 'f':
apk_flags |= APK_FORCE;
apk_force |= APK_FORCE_OVERWRITE | APK_FORCE_OLD_APK
| APK_FORCE_BROKEN_WORLD | APK_FORCE_NON_REPOSITORY
| APK_FORCE_BINARY_STDOUT;
break;
case 0x120:
apk_force |= APK_FORCE_OVERWRITE;
break;
case 0x121:
apk_force |= APK_FORCE_OLD_APK;
break;
case 0x122:
apk_force |= APK_FORCE_BROKEN_WORLD;
break;
case 0x123:
apk_force |= APK_FORCE_REFRESH;
break;
case 0x124:
apk_force |= APK_FORCE_NON_REPOSITORY;
break;
case 0x125:
apk_force |= APK_FORCE_BINARY_STDOUT;
break;
case 'i':
apk_flags |= APK_INTERACTIVE;
......@@ -166,7 +186,13 @@ static const struct apk_option options_global[] = {
{ 'v', "verbose", "Print more information (can be doubled)" },
{ 'i', "interactive", "Ask confirmation for certain operations" },
{ 'V', "version", "Print program version and exit" },
{ 'f', "force", "Do what was asked even if it looks dangerous" },
{ 'f', "force", "Enable selected --force-* (deprecated)" },
{ 0x125, "force-binary-stdout", "Continue even if binary data is to be output" },
{ 0x122, "force-broken-world", "Continue even if 'world' cannot be satisfied" },
{ 0x124, "force-non-repository", "Continue even if packages may be lost on reboot" },
{ 0x121, "force-old-apk", "Continue even if packages use unsupported features" },
{ 0x120, "force-overwrite", "Overwrite files in other packages" },
{ 0x123, "force-refresh", "Do not use cached files (local or from proxy)" },
{ 'U', "update-cache", "Update the repository cache" },
{ 0x101, "progress", "Show a progress bar" },
{ 0x10f, "progress-fd", "Write progress to fd", required_argument, "FD" },
......@@ -182,7 +208,7 @@ static const struct apk_option options_global[] = {
{ 0x108, "repositories-file", "Override repositories file",
required_argument, "REPOFILE" },
{ 0x109, "no-network", "Do not use network (cache is still used)" },
{ 0x115, "no-cache", "Read uncached index from network" },
{ 0x115, "no-cache", "Do not use any local cache path" },
{ 0x116, "cache-dir", "Override cache directory",
required_argument, "CACHEDIR" },
{ 0x112, "arch", "Use architecture with --root",
......@@ -217,6 +243,15 @@ static int option_parse_commit(void *ctx, struct apk_db_options *dbopts, int opt
case 0x113:
apk_flags |= APK_NO_SCRIPTS;
break;
case 0x117:
apk_flags |= APK_NO_COMMIT_HOOKS;
break;
case 0x118:
dbopts->open_flags |= APK_OPENF_CREATE;
apk_flags |= APK_NO_COMMIT_HOOKS;
apk_force |= APK_FORCE_OVERWRITE | APK_FORCE_OLD_APK
| APK_FORCE_BROKEN_WORLD | APK_FORCE_NON_REPOSITORY;
break;
default:
return -ENOTSUP;
}
......@@ -228,6 +263,9 @@ static const struct apk_option options_commit[] = {
{ 0x102, "clean-protected", "Do not create .apk-new files in configuration dirs" },
{ 0x111, "overlay-from-stdin", "Read list of overlay files from stdin" },
{ 0x113, "no-scripts", "Do not execute any scripts" },
{ 0x117, "no-commit-hooks", "Skip pre/post hook scripts (but not other scripts)" },
{ 0x118, "initramfs-diskless-boot",
"Enables options for diskeless initramfs boot (e.g. skip hooks)" },
};
const struct apk_option_group optgroup_commit = {
......
......@@ -60,11 +60,10 @@ static inline int IS_ERR_OR_NULL(const void *ptr) { return IS_ERR(ptr) || !ptr;
#endif
extern int apk_verbosity;
extern unsigned int apk_flags;
extern unsigned int apk_flags, apk_force;
extern const char *apk_arch;
extern char **apk_argv;
#define APK_FORCE 0x0001
#define APK_SIMULATE 0x0002
#define APK_CLEAN_PROTECTED 0x0004
#define APK_PROGRESS 0x0008
......@@ -77,6 +76,14 @@ extern char **apk_argv;
#define APK_OVERLAY_FROM_STDIN 0x2000
#define APK_NO_SCRIPTS 0x4000
#define APK_NO_CACHE 0x8000
#define APK_NO_COMMIT_HOOKS 0x00010000
#define APK_FORCE_OVERWRITE BIT(0)
#define APK_FORCE_OLD_APK BIT(1)
#define APK_FORCE_BROKEN_WORLD BIT(2)
#define APK_FORCE_REFRESH BIT(3)
#define APK_FORCE_NON_REPOSITORY BIT(4)
#define APK_FORCE_BINARY_STDOUT BIT(5)
/* default architecture for APK packages. */
#if defined(__x86_64__)
......
......@@ -236,6 +236,10 @@ static int run_commit_hook(void *ctx, int dirfd, const char *file)
return 0;
snprintf(fn, sizeof(fn), "etc/apk/commit_hooks.d" "/%s", file);
if ((apk_flags & APK_NO_COMMIT_HOOKS) != 0) {
apk_message("Skipping: %s %s", fn, commit_hook_str[hook->type]);
return 0;
}
if (apk_verbosity >= 2) apk_message("Executing: %s %s", fn, commit_hook_str[hook->type]);
if (apk_db_run_script(db, fn, argv) < 0 && hook->type == PRE_COMMIT_HOOK)
......@@ -262,7 +266,8 @@ int apk_solver_commit_changeset(struct apk_database *db,
int r, errors = 0;
if (apk_db_check_world(db, world) != 0) {
apk_error("Not committing changes due to missing repository tags. Use --force to override.");
apk_error("Not committing changes due to missing repository tags. "
"Use --force-broken-world to override.");
return -1;
}
......@@ -456,7 +461,8 @@ static void print_conflicts(struct print_state *ps, struct apk_package *pkg)
if (d->version == &apk_null_blob &&
p->version == &apk_null_blob)
continue;
if (once && p->pkg == pkg) {
if (once && p->pkg == pkg &&
p->version == d->version) {
once = 0;
continue;
}
......@@ -670,7 +676,8 @@ int apk_solver_commit(struct apk_database *db,
int r;
if (apk_db_check_world(db, world) != 0) {
apk_error("Not committing changes due to missing repository tags. Use --force to override.");
apk_error("Not committing changes due to missing repository tags. "
"Use --force-broken-world to override.");
return -1;
}
......
......@@ -47,7 +47,7 @@ enum {
};
int apk_verbosity = 1;
unsigned int apk_flags = 0;
unsigned int apk_flags = 0, apk_force = 0;
static apk_blob_t tmpprefix = { .len=8, .ptr = ".apknew." };
......@@ -262,12 +262,16 @@ void apk_db_dir_unref(struct apk_database *db, struct apk_db_dir *dir, int rmdir
db->installed.stats.dirs--;
apk_protected_path_array_free(&dir->protected_paths);
if (dir->namelen != 0) {
if (rmdir_mode == APK_DIR_REMOVE && !(apk_flags & APK_SIMULATE))
if (unlinkat(db->root_fd, dir->name, AT_REMOVEDIR))
if (rmdir_mode == APK_DIR_REMOVE) {
dir->modified = 1;
if (!(apk_flags & APK_SIMULATE) &&
unlinkat(db->root_fd, dir->name, AT_REMOVEDIR) != 0)
;
}
apk_db_dir_unref(db, dir->parent, rmdir_mode);
dir->parent = NULL;
}
apk_hash_delete_hashed(&db->installed.dirs, APK_BLOB_PTR_LEN(dir->name, dir->namelen), dir->hash);
dir->seen = dir->created = dir->update_permissions = 0;
}
struct apk_db_dir *apk_db_dir_ref(struct apk_db_dir *dir)
......@@ -291,26 +295,25 @@ struct apk_db_dir *apk_db_dir_get(struct apk_database *db, apk_blob_t name)
unsigned long hash = apk_hash_from_key(&db->installed.dirs, name);
char *relative_name;
if (name.len && name.ptr[name.len-1] == '/')
name.len--;
if (name.len && name.ptr[name.len-1] == '/') name.len--;
dir = (struct apk_db_dir *) apk_hash_get_hashed(&db->installed.dirs, name, hash);
if (dir != NULL)
return apk_db_dir_ref(dir);
if (dir != NULL && dir->refs) return apk_db_dir_ref(dir);
if (dir == NULL) {
dir = calloc(1, sizeof(*dir) + name.len + 1);
dir->rooted_name[0] = '/';
memcpy(dir->name, name.ptr, name.len);
dir->name[name.len] = 0;
dir->namelen = name.len;
dir->hash = hash;
apk_protected_path_array_init(&dir->protected_paths);
apk_hash_insert_hashed(&db->installed.dirs, dir, hash);
}
db->installed.stats.dirs++;
dir = malloc(sizeof(*dir) + name.len + 1);
memset(dir, 0, sizeof(*dir));
dir->refs = 1;
dir->uid = (uid_t) -1;
dir->gid = (gid_t) -1;
dir->rooted_name[0] = '/';
memcpy(dir->name, name.ptr, name.len);
dir->name[name.len] = 0;
dir->namelen = name.len;
dir->hash = hash;
apk_protected_path_array_init(&dir->protected_paths);
apk_hash_insert_hashed(&db->installed.dirs, dir, hash);
if (name.len == 0) {
dir->parent = NULL;
......@@ -630,7 +633,7 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
r = apk_repo_format_real_url(db, repo, pkg, url, sizeof(url));
if (r < 0) return r;
if ((apk_flags & APK_FORCE) ||
if ((apk_force & APK_FORCE_REFRESH) ||
fstatat(db->cache_fd, cacheitem, &st, 0) != 0)
st.st_mtime = 0;
......@@ -864,13 +867,13 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
case 's': ipkg->broken_script = 1; break;
case 'x': ipkg->broken_xattr = 1; break;
default:
if (!(apk_flags & APK_FORCE))
if (!(apk_force & APK_FORCE_OLD_APK))
goto old_apk_tools;
}
}
break;
default:
if (r != 0 && !(apk_flags & APK_FORCE))
if (r != 0 && !(apk_force & APK_FORCE_OLD_APK))
goto old_apk_tools;
/* Installed. So mark the package as installable. */
pkg->filename = NULL;
......@@ -2030,7 +2033,7 @@ int apk_db_check_world(struct apk_database *db, struct apk_dependency_array *wor
struct apk_dependency *dep;
int bad = 0, tag;
if (apk_flags & APK_FORCE)
if (apk_force & APK_FORCE_BROKEN_WORLD)
return 0;
foreach_array_item(dep, world) {
......@@ -2460,7 +2463,7 @@ static int apk_db_install_archive_entry(void *_ctx,
if (pkg_prio >= 0)
break;
if (!(apk_flags & APK_FORCE)) {
if (!(apk_force & APK_FORCE_OVERWRITE)) {
apk_error(PKG_VER_FMT": trying to overwrite %s owned by "PKG_VER_FMT".",
PKG_VER_PRINTF(pkg), ae->name, PKG_VER_PRINTF(opkg));
ipkg->broken_files = 1;
......
......@@ -242,12 +242,15 @@ static void mark_name_recursive(struct apk_database *db, const char *match, stru
apk_dependency_array_init(&world);
*apk_dependency_array_add(&world) = dep;
r = apk_solver_solve(db, 0, world, &changeset);
apk_dependency_array_free(&world);
if (r == 0) {
foreach_array_item(change, changeset.changes)
mark_package(ctx, change->new_pkg);
} else
} else {
mark_error(ctx, match, name);
if (apk_verbosity > 1)
apk_solver_print_errors(db, &changeset, world);
}
apk_dependency_array_free(&world);
apk_change_array_free(&changeset.changes);
}
......@@ -316,8 +319,7 @@ static int fetch_main(void *pctx, struct apk_database *db, struct apk_string_arr
ctx->outdir_fd = AT_FDCWD;
if ((args->num == 1) && (strcmp(args->item[0], "coffee") == 0)) {
if (apk_flags & APK_FORCE)
return cup();
if (apk_force) return cup();
apk_message("Go and fetch your own coffee.");
return 0;
}
......
......@@ -67,6 +67,7 @@ static const struct apk_option_group optgroup_applet = {
static int mark_recalculate(apk_hash_item item, void *ctx)
{
struct apk_db_dir *dir = (struct apk_db_dir *) item;
if (dir->refs == 0) return 0;
dir->update_permissions = 1;
return 0;
}
......
......@@ -118,9 +118,9 @@ static int index_main(void *ctx, struct apk_database *db, struct apk_string_arra
char **parg;
if (isatty(STDOUT_FILENO) && ictx->output == NULL &&
!(apk_flags & APK_FORCE)) {
apk_error("Will not write binary index to console "
"without --force");
!(apk_force & APK_FORCE_BINARY_STDOUT)) {
apk_error("Will not write binary index to console. "
"Use --force-binary-stdout to override.");
return -1;
}
......
......@@ -184,55 +184,57 @@ static void discover_name(struct apk_solver_state *ss, struct apk_name *name)
name->ss.no_iif = 1;
foreach_array_item(p, name->providers) {
struct apk_package *pkg = p->pkg;
if (pkg->ss.seen)
continue;
if (!pkg->ss.seen) {
pkg->ss.seen = 1;
pkg->ss.pinning_allowed = APK_DEFAULT_PINNING_MASK;
pkg->ss.pinning_preferred = APK_DEFAULT_PINNING_MASK;
pkg->ss.pkg_available =
(pkg->filename != NULL) ||
(pkg->repos & db->available_repos & ~BIT(APK_REPOSITORY_CACHED));
/* Package is in 'cached' repository if filename is provided,
* or it's a 'virtual' package with install_size zero */
pkg->ss.pkg_selectable =
(pkg->repos & db->available_repos) ||
pkg->cached_non_repository ||
pkg->ipkg;
/* Prune install_if packages that are no longer available,
* currently works only if SOLVERF_AVAILABLE is set in the
* global solver flags. */
pkg->ss.iif_failed =
(pkg->install_if->num == 0) ||
((ss->solver_flags_inherit & APK_SOLVERF_AVAILABLE) &&
!pkg->ss.pkg_available);
repos = get_pkg_repos(db, pkg);
pkg->ss.tag_preferred =
(pkg->filename != NULL) ||
(pkg->installed_size == 0) ||
(repos & ss->default_repos);
pkg->ss.tag_ok =
pkg->ss.tag_preferred ||
pkg->cached_non_repository ||
pkg->ipkg;
pkg->ss.seen = 1;
pkg->ss.pinning_allowed = APK_DEFAULT_PINNING_MASK;
pkg->ss.pinning_preferred = APK_DEFAULT_PINNING_MASK;
pkg->ss.pkg_available =
(pkg->filename != NULL) ||
(pkg->repos & db->available_repos & ~BIT(APK_REPOSITORY_CACHED));
/* Package is in 'cached' repository if filename is provided,
* or it's a 'virtual' package with install_size zero */
pkg->ss.pkg_selectable =
(pkg->repos & db->available_repos) ||
pkg->cached_non_repository ||
pkg->ipkg;
/* Prune install_if packages that are no longer available,
* currently works only if SOLVERF_AVAILABLE is set in the
* global solver flags. */
pkg->ss.iif_failed =
(pkg->install_if->num == 0) ||
((ss->solver_flags_inherit & APK_SOLVERF_AVAILABLE) &&
!pkg->ss.pkg_available);
name->ss.no_iif &= pkg->ss.iif_failed;
foreach_array_item(dep, pkg->depends) {
discover_name(ss, dep->name);
pkg->ss.max_dep_chain = max(pkg->ss.max_dep_chain,
dep->name->ss.max_dep_chain+1);
}
repos = get_pkg_repos(db, pkg);
pkg->ss.tag_preferred =
(pkg->filename != NULL) ||
(pkg->installed_size == 0) ||
(repos & ss->default_repos);
pkg->ss.tag_ok =
pkg->ss.tag_preferred ||
pkg->cached_non_repository ||
pkg->ipkg;
foreach_array_item(dep, pkg->depends) {
discover_name(ss, dep->name);
pkg->ss.max_dep_chain = max(pkg->ss.max_dep_chain,
dep->name->ss.max_dep_chain+1);
dbg_printf("discover " PKG_VER_FMT ": tag_ok=%d, tag_pref=%d max_dep_chain=%d selectable=%d\n",
PKG_VER_PRINTF(pkg),
pkg->ss.tag_ok,
pkg->ss.tag_preferred,
pkg->ss.max_dep_chain,
pkg->ss.pkg_selectable);
}
name->ss.no_iif &= pkg->ss.iif_failed;
name->ss.max_dep_chain = max(name->ss.max_dep_chain, pkg->ss.max_dep_chain);
dbg_printf("discover " PKG_VER_FMT ": tag_ok=%d, tag_pref=%d max_dep_chain=%d selectable=%d\n",
PKG_VER_PRINTF(pkg),
pkg->ss.tag_ok,
pkg->ss.tag_preferred,
pkg->ss.max_dep_chain,
pkg->ss.pkg_selectable);
dbg_printf("discover %s: max_dep_chain=%d no_iif=%d\n",
name->name, name->ss.max_dep_chain, name->ss.no_iif);
}
foreach_array_item(pname0, name->rinstall_if)
discover_name(ss, *pname0);
......@@ -398,10 +400,11 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
foreach_array_item(dep, pkg->install_if)
inherit_pinning_and_flags(ss, pkg, dep->name->ss.chosen.pkg);
}
dbg_printf(" "PKG_VER_FMT": iif_triggered=%d iif_failed=%d\n",
PKG_VER_PRINTF(pkg), pkg->ss.iif_triggered, pkg->ss.iif_failed);
has_iif |= pkg->ss.iif_triggered;
no_iif &= pkg->ss.iif_failed;
dbg_printf(" "PKG_VER_FMT": iif_triggered=%d iif_failed=%d, no_iif=%d\n",
PKG_VER_PRINTF(pkg), pkg->ss.iif_triggered, pkg->ss.iif_failed,
no_iif);
if (name->ss.requirers == 0)
continue;
......@@ -996,7 +999,7 @@ restart:
generate_changeset(ss, world);
if (ss->errors && (apk_flags & APK_FORCE)) {
if (ss->errors && (apk_force & APK_FORCE_BROKEN_WORLD)) {
foreach_array_item(d, world) {
name = d->name;
pkg = name->ss.chosen.pkg;
......
......@@ -144,7 +144,8 @@ static int upgrade_main(void *ctx, struct apk_database *db, struct apk_string_ar
int r = 0;
if (apk_db_check_world(db, db->world) != 0) {
apk_error("Not continuing with upgrade due to missing repository tags. Use --force to override.");
apk_error("Not continuing with upgrade due to missing repository tags. "
"Use --force-broken-world to override.");
return -1;
}
......
......@@ -120,7 +120,7 @@ static struct apk_istream *apk_istream_fetch(const char *url, time_t since)
if (!fis || !u) goto err;
u->last_modified = since;
io = fetchXGet(u, &fis->urlstat, "i");
io = fetchXGet(u, &fis->urlstat, (apk_force & APK_FORCE_REFRESH) ? "Ci" : "i");
if (!io) {
rc = fetch_maperror(fetchLastErrCode);
goto err;
......
......@@ -46,3 +46,23 @@ I:1
D:app
i:app bar
C:Q1/hQ3fH2AzuTwJVGOz+keypXhXKY=
P:dam
V:1
S:1
I:1
C:Q1/hQ3fH2AzuTwJVGfz+keypXhXKY=
P:dam-babel
V:1
S:1
I:1
p:cmd:babel
C:Q1/hQ3fH2AguTwJVGOz+keypXhXKY=
P:dam1-babel
V:1
S:1
I:1
i:dam dam-babel
p:cmd:babel
@ARGS
--test-repo installif1.repo
add dam dam-babel cmd:babel
@EXPECT
(1/3) Installing dam-babel (1)
(2/3) Installing dam (1)
(3/3) Installing dam1-babel (1)
OK: 0 MiB in 0 packages
......@@ -67,3 +67,38 @@ S:1
I:1
p:selfprovided=2
p:selfprovided=3
C:Q1EyN5AdpAOBJWKMR89ppC66aaaaj=
P:conflicted-provider-a
V:0.1
S:1
I:1
p:conflicted-provider
C:Q1EyN5AdpAOBJWKMR89ppC66bbbbj=
P:conflicted-provider-b
V:0.1
S:1
I:1
p:conflicted-provider
C:Q1EyN5AdpAOBJWKMR89ppC66ccccj=
P:conflicted-dep
V:0.1
S:1
I:1
D:conflicted-provider
C:Q1EyN5AdpAOBJWKMR89ppC66ddddj=
P:conflicted-parent
V:0.1
S:1
I:1
D:conflicted-dep
C:Q1Eyd5AdpAOBJWKMR89ppC66bbbbj=
P:self-provide
V:0.1
S:1
I:1
p:self-provide
@ARGS
--test-repo provides.repo
add self-provide
@EXPECT
ERROR: unsatisfiable constraints:
self-provide-0.1:
conflicts: self-provide-0.1[self-provide]
satisfies: world[self-provide]