Teach git-credential-store to read/write credentials from $XDG_CONFIG_HOME/git/credentials and ~/.git-credentials where appropriate: * get: call lookup_credential() on the XDG file first if it exists. If the credential can't be found, call lookup_credential() on the HOME file. * erase: Call remove_credential() on both the XDG file if it exists and the HOME file if it exists. * store: If the XDG file exists, call store_credential() on the XDG file and remove_credential() on the HOME file to prevent duplicates. * If "--file" is provided, use the file for all operations instead. In order to support the above, parse_credential_file() now returns 1 if it finds a matching credential, and 0 if it does not. Likewise, lookup_credential() returns 1 if it could find the credential, and 0 if it could not. Signed-off-by: Paul Tan <pyokagan@xxxxxxxxx> --- credential-store.c | 60 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/credential-store.c b/credential-store.c index 925d3f4..18b8897 100644 --- a/credential-store.c +++ b/credential-store.c @@ -6,7 +6,7 @@ static struct lock_file credential_lock; -static void parse_credential_file(const char *fn, +static int parse_credential_file(const char *fn, struct credential *c, void (*match_cb)(struct credential *), void (*other_cb)(struct strbuf *)) @@ -14,18 +14,20 @@ static void parse_credential_file(const char *fn, FILE *fh; struct strbuf line = STRBUF_INIT; struct credential entry = CREDENTIAL_INIT; + int found_credential = 0; fh = fopen(fn, "r"); if (!fh) { if (errno != ENOENT) die_errno("unable to open %s", fn); - return; + return 0; } while (strbuf_getline(&line, fh, '\n') != EOF) { credential_from_url(&entry, line.buf); if (entry.username && entry.password && credential_match(c, &entry)) { + found_credential = 1; if (match_cb) { match_cb(&entry); break; @@ -38,6 +40,7 @@ static void parse_credential_file(const char *fn, credential_clear(&entry); strbuf_release(&line); fclose(fh); + return found_credential; } static void print_entry(struct credential *c) @@ -111,8 +114,7 @@ static void remove_credential(const char *fn, struct credential *c) static int lookup_credential(const char *fn, struct credential *c) { - parse_credential_file(fn, c, print_entry, NULL); - return c->username && c->password; + return parse_credential_file(fn, c, print_entry, NULL); } int main(int argc, char **argv) @@ -124,6 +126,9 @@ int main(int argc, char **argv) const char *op; struct credential c = CREDENTIAL_INIT; char *file = NULL; + char *home_file = NULL; + char *xdg_file = NULL; + int ret = 0; struct option options[] = { OPT_STRING(0, "file", &file, "path", "fetch and store credentials in <path>"), @@ -137,21 +142,46 @@ int main(int argc, char **argv) usage_with_options(usage, options); op = argv[0]; - if (!file) - file = expand_user_path("~/.git-credentials"); - if (!file) - die("unable to set up default path; use --file"); + if (!file) { + home_config_paths(NULL, &xdg_file, "credentials"); + home_file = expand_user_path("~/.git-credentials"); + if (!xdg_file && !home_file) + die("unable to set up default path; use --file"); + } if (credential_read(&c, stdin) < 0) die("unable to read credential"); - if (!strcmp(op, "get")) - lookup_credential(file, &c); - else if (!strcmp(op, "erase")) - remove_credential(file, &c); - else if (!strcmp(op, "store")) - store_credential(file, &c); - else + if (!strcmp(op, "get")) { + if (file) { + lookup_credential(file, &c); + } else { + if (xdg_file && access_or_warn(xdg_file, R_OK, 0) == 0) + ret = lookup_credential(xdg_file, &c); + if (!ret && home_file && access_or_warn(home_file, R_OK, 0) == 0) + lookup_credential(home_file, &c); + } + } else if (!strcmp(op, "erase")) { + if (file) { + remove_credential(file, &c); + } else { + if (xdg_file && access(xdg_file, F_OK) == 0) + remove_credential(xdg_file, &c); + if (home_file && access(home_file, F_OK) == 0) + remove_credential(home_file, &c); + } + } else if (!strcmp(op, "store")) { + if (file) { + store_credential(file, &c); + } else if (xdg_file && access(xdg_file, F_OK) == 0) { + store_credential(xdg_file, &c); + if (home_file && access(home_file, F_OK) == 0 && + c.protocol && (c.host || c.path) && c.username + && c.password) + remove_credential(home_file, &c); + } else + store_credential(home_file, &c); + } else ; /* Ignore unknown operation. */ return 0; -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html