git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Support "core.excludesfile = ~/.gitignore"
@ 2008-08-22  4:14 Karl Chen
  2008-08-22 16:58 ` Eric Raible
  2008-08-22 21:10 ` Junio C Hamano
  0 siblings, 2 replies; 47+ messages in thread
From: Karl Chen @ 2008-08-22  4:14 UTC (permalink / raw)
  To: git


I keep my rc files, including .gitconfig and my default gitignore
list under version control and like to have the same contents
everywhere.  Unfortunately my home directory is at different
locations on different systems.

I'd like to be able to put something like this in my ~/.gitconfig:

[core]
        excludesfile = ~/.gitignore

or
        excludesfile = $HOME/.gitignore

Another idea is to have a non-absolute path be interpreted
relative to the location of .gitconfig, i.e. $HOME, instead of the
current directory.  $GIT_DIR/info/excludes is already for
repository-specific excludes so no functionality would be lost.


Below is a sample patch that works for me.  We could also use
getpwuid(getuid()) instead of getenv("HOME") to be consistent with
user_path() but this is simpler and arguably more likely what the
user wants when it matters.


>From 6eb18f8ade791521bdad955e1da2b40399a426f0 Mon Sep 17 00:00:00 2001
From: Karl Chen <quarl@quarl.org>
Date: Thu, 21 Aug 2008 21:00:26 -0700
Subject: [PATCH] Support "core.excludesfile = ~/.gitignore"

The config variable core.excludesfile is parsed to substitute leading "~/"
with getenv("HOME").

Signed-off-by: Karl Chen <quarl@quarl.org>

---
 config.c |   20 ++++++++++++++++++--
 1 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/config.c b/config.c
index 53f04a0..41061d2 100644
--- a/config.c
+++ b/config.c
@@ -334,6 +334,18 @@ int git_config_string(const char **dest, const char *var, const char *value)
 	return 0;
 }
 
+static char const *git_config_subst_userdir(char const *value) {
+	if (value[0] == '~' && value[1] == '/') {
+		const char *home = getenv("HOME");
+		char *userdir_excludes_file = malloc(strlen(home) + strlen(value)-1 + 1);
+		strcpy(userdir_excludes_file, home);
+		strcat(userdir_excludes_file, value+1);
+		return userdir_excludes_file;
+	} else {
+		return xstrdup(value);
+	}
+}
+
 static int git_default_core_config(const char *var, const char *value)
 {
 	/* This needs a better name */
@@ -456,8 +468,12 @@ static int git_default_core_config(const char *var, const char *value)
 	if (!strcmp(var, "core.editor"))
 		return git_config_string(&editor_program, var, value);
 
-	if (!strcmp(var, "core.excludesfile"))
-		return git_config_string(&excludes_file, var, value);
+	if (!strcmp(var, "core.excludesfile")) {
+		if (!value)
+			return config_error_nonbool(var);
+		excludes_file = git_config_subst_userdir(value);
+		return 0;
+	}
 
 	if (!strcmp(var, "core.whitespace")) {
 		if (!value)
-- 
1.5.6.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread
* [PATCH v3] Expand ~ and ~user in core.excludesfile, commit.template
@ 2009-11-18  7:29 Matthieu Moy
  2009-11-18  8:58 ` [PATCH v4] " Matthieu Moy
  0 siblings, 1 reply; 47+ messages in thread
From: Matthieu Moy @ 2009-11-18  7:29 UTC (permalink / raw)
  To: git, gitster; +Cc: Matthieu Moy, Karl Chen

These config variables are parsed to substitute ~ and ~user with getpw
entries.

user_path() refactored into new function expand_user_path(), to allow
dynamically allocating the return buffer.

Original patch by Karl Chen, modified by Matthieu Moy, and further
amended by Junio C Hamano.

Signed-off-by: Karl Chen <quarl@quarl.org>
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---

Since v2, I changed the code to use $HOME instead of the actual home
to expand ~.

This way, if you run "HOME=/else/where/ git status", then both
.gitconfig and ~/.gitignore will be taken from /else/where.

 Documentation/config.txt |    7 +++-
 builtin-commit.c         |    2 +-
 cache.h                  |    2 +
 config.c                 |   12 ++++++-
 path.c                   |   83 +++++++++++++++++++++++++++------------------
 5 files changed, 69 insertions(+), 37 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index cb73d75..fb1740c 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -380,8 +380,9 @@ Common unit suffixes of 'k', 'm', or 'g' are supported.
 core.excludesfile::
 	In addition to '.gitignore' (per-directory) and
 	'.git/info/exclude', git looks into this file for patterns
-	of files which are not meant to be tracked.  See
-	linkgit:gitignore[5].
+	of files which are not meant to be tracked.  "~/" is expanded
+	to the value of `$HOME` and "~user/" to the specified user's
+	home directory.  See linkgit:gitignore[5].
 
 core.editor::
 	Commands such as `commit` and `tag` that lets you edit
@@ -670,6 +671,8 @@ color.ui::
 
 commit.template::
 	Specify a file to use as the template for new commit messages.
+	"~/" is expanded to the value of `$HOME` and "~user/" to the
+	specified user's home directory.
 
 diff.autorefreshindex::
 	When using 'git-diff' to compare with work tree
diff --git a/builtin-commit.c b/builtin-commit.c
index d525b89..09d2840 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -999,7 +999,7 @@ static int git_commit_config(const char *k, const char *v, void *cb)
 	struct wt_status *s = cb;
 
 	if (!strcmp(k, "commit.template"))
-		return git_config_string(&template_file, k, v);
+		return git_config_pathname(&template_file, k, v);
 
 	return git_status_config(k, v, s);
 }
diff --git a/cache.h b/cache.h
index 71a731d..42f7cd8 100644
--- a/cache.h
+++ b/cache.h
@@ -645,6 +645,7 @@ int set_shared_perm(const char *path, int mode);
 #define adjust_shared_perm(path) set_shared_perm((path), 0)
 int safe_create_leading_directories(char *path);
 int safe_create_leading_directories_const(const char *path);
+extern char *expand_user_path(const char *path);
 char *enter_repo(char *path, int strict);
 static inline int is_absolute_path(const char *path)
 {
@@ -903,6 +904,7 @@ extern unsigned long git_config_ulong(const char *, const char *);
 extern int git_config_bool_or_int(const char *, const char *, int *);
 extern int git_config_bool(const char *, const char *);
 extern int git_config_string(const char **, const char *, const char *);
+extern int git_config_pathname(const char **, const char *, const char *);
 extern int git_config_set(const char *, const char *);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
diff --git a/config.c b/config.c
index c644061..b3d1ff4 100644
--- a/config.c
+++ b/config.c
@@ -351,6 +351,16 @@ int git_config_string(const char **dest, const char *var, const char *value)
 	return 0;
 }
 
+int git_config_pathname(const char **dest, const char *var, const char *value)
+{
+	if (!value)
+		return config_error_nonbool(var);
+	*dest = expand_user_path(value);
+	if (!*dest)
+		die("Failed to expand user dir in: '%s'", value);
+	return 0;
+}
+
 static int git_default_core_config(const char *var, const char *value)
 {
 	/* This needs a better name */
@@ -474,7 +484,7 @@ static int git_default_core_config(const char *var, const char *value)
 		return git_config_string(&editor_program, var, value);
 
 	if (!strcmp(var, "core.excludesfile"))
-		return git_config_string(&excludes_file, var, value);
+		return git_config_pathname(&excludes_file, var, value);
 
 	if (!strcmp(var, "core.whitespace")) {
 		if (!value)
diff --git a/path.c b/path.c
index 047fdb0..6351b57 100644
--- a/path.c
+++ b/path.c
@@ -11,6 +11,7 @@
  * which is what it's designed for.
  */
 #include "cache.h"
+#include "strbuf.h"
 
 static char bad_path[] = "/bad-path/";
 
@@ -207,43 +208,49 @@ int validate_headref(const char *path)
 	return -1;
 }
 
-static char *user_path(char *buf, char *path, int sz)
+static struct passwd *getpw_str(const char *username, size_t len)
 {
 	struct passwd *pw;
-	char *slash;
-	int len, baselen;
+	char *username_z = xmalloc(len + 1);
+	memcpy(username_z, username, len);
+	username_z[len] = '\0';
+	pw = getpwnam(username_z);
+	free(username_z);
+	return pw;
+}
 
-	if (!path || path[0] != '~')
-		return NULL;
-	path++;
-	slash = strchr(path, '/');
-	if (path[0] == '/' || !path[0]) {
-		pw = getpwuid(getuid());
-	}
-	else {
-		if (slash) {
-			*slash = 0;
-			pw = getpwnam(path);
-			*slash = '/';
+/*
+ * Return a string with ~ and ~user expanded via getpw*.  If buf != NULL,
+ * then it is a newly allocated string. Returns NULL on getpw failure or
+ * if path is NULL.
+ */
+char *expand_user_path(const char *path)
+{
+	struct strbuf user_path = STRBUF_INIT;
+	const char *first_slash = strchrnul(path, '/');
+	const char *to_copy = path;
+
+	if (path == NULL)
+		goto return_null;
+	if (path[0] == '~') {
+		const char *username = path + 1;
+		size_t username_len = first_slash - username;
+		if (username_len == 0) {
+			const char * home = getenv("HOME");
+			strbuf_add(&user_path, home, strlen(home));
+		} else {
+			struct passwd *pw = getpw_str(username, username_len);
+			if (!pw)
+				goto return_null;
+			strbuf_add(&user_path, pw->pw_dir, strlen(pw->pw_dir));
 		}
-		else
-			pw = getpwnam(path);
+		to_copy = first_slash;
 	}
-	if (!pw || !pw->pw_dir || sz <= strlen(pw->pw_dir))
-		return NULL;
-	baselen = strlen(pw->pw_dir);
-	memcpy(buf, pw->pw_dir, baselen);
-	while ((1 < baselen) && (buf[baselen-1] == '/')) {
-		buf[baselen-1] = 0;
-		baselen--;
-	}
-	if (slash && slash[1]) {
-		len = strlen(slash);
-		if (sz <= baselen + len)
-			return NULL;
-		memcpy(buf + baselen, slash, len + 1);
-	}
-	return buf;
+	strbuf_add(&user_path, to_copy, strlen(to_copy));
+	return strbuf_detach(&user_path, NULL);
+return_null:
+	strbuf_release(&user_path);
+	return NULL;
 }
 
 /*
@@ -291,8 +298,18 @@ char *enter_repo(char *path, int strict)
 		if (PATH_MAX <= len)
 			return NULL;
 		if (path[0] == '~') {
-			if (!user_path(used_path, path, PATH_MAX))
+			char *newpath = expand_user_path(path);
+			if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
+				free(newpath);
 				return NULL;
+			}
+			/*
+			 * Copy back into the static buffer. A pity
+			 * since newpath was not bounded, but other
+			 * branches of the if are limited by PATH_MAX
+			 * anyway.
+			 */
+			strcpy(used_path, newpath); free(newpath);
 			strcpy(validated_path, path);
 			path = used_path;
 		}
-- 
1.6.5.2.152.gbbe9e

^ permalink raw reply related	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2009-11-19 18:13 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-08-22  4:14 [PATCH] Support "core.excludesfile = ~/.gitignore" Karl Chen
2008-08-22 16:58 ` Eric Raible
2008-08-22 17:56   ` Bert Wesarg
2008-08-22 21:10 ` Junio C Hamano
2008-08-24  8:40   ` Karl Chen
2008-08-24 18:11     ` Junio C Hamano
2008-08-24 22:08       ` Jeff King
2008-08-24 22:59         ` Junio C Hamano
2008-08-24 23:13           ` Jeff King
2008-08-24 23:40             ` Junio C Hamano
2008-08-24 23:51               ` limiting relationship of git dir and worktree (was Re: [PATCH] Support "core.excludesfile = ~/.gitignore") Jeff King
2008-08-25  0:30                 ` Dropping core.worktree and GIT_WORK_TREE support (was Re: limiting relationship of git dir and worktree) Junio C Hamano
2008-08-25  2:00                   ` Miklos Vajna
2008-08-25  3:05                     ` Dropping core.worktree and GIT_WORK_TREE support Junio C Hamano
2008-08-25 12:52                       ` Miklos Vajna
2008-08-25 13:52                         ` Nguyen Thai Ngoc Duy
2008-08-25 14:43                           ` [PATCH] git diff/diff-index/diff-files: call setup_work_tree() Miklos Vajna
2008-08-25 14:46                             ` Nguyen Thai Ngoc Duy
2008-08-25 14:50                               ` Miklos Vajna
2008-08-25 15:11                                 ` Miklos Vajna
2008-08-25 15:26                                   ` Nguyen Thai Ngoc Duy
2008-08-26 23:58                                     ` Junio C Hamano
2008-08-28 13:02                                       ` [PATCH] diff*: fix worktree setup Nguyễn Thái Ngọc Duy
2008-08-25 21:21                         ` Dropping core.worktree and GIT_WORK_TREE support Junio C Hamano
2008-08-25 21:37                           ` Miklos Vajna
2008-08-26  7:35                   ` Dropping core.worktree and GIT_WORK_TREE support (was Re: limiting relationship of git dir and worktree) Michael J Gruber
2008-08-27  0:49                     ` Jeff King
2008-08-25 19:07               ` [PATCH v2] Support "core.excludesfile = ~/.gitignore" Karl Chen
2008-08-26  6:42                 ` Johannes Sixt
2008-08-27  0:25                 ` Jeff King
2008-08-27  3:12                   ` Karl Chen
2008-08-27  5:01                     ` Junio C Hamano
2008-08-28  9:09                       ` [PATCH v3] Expand ~ and ~user in core.excludesfile, commit.template Karl Chen
2008-08-29  3:26                         ` Jeff King
2008-08-29  4:08                           ` Junio C Hamano
2008-08-29  9:29                             ` [PATCH v4] " Karl Chen
2008-08-29 16:08                               ` Junio C Hamano
2008-08-29 19:01                                 ` Karl Chen
2008-08-29 19:28                                   ` Junio C Hamano
2008-08-29 22:34                                     ` Karl Chen
2008-08-30  5:31                                       ` Junio C Hamano
2008-08-30  6:02                               ` Jeff King
2008-08-29  7:00                         ` [PATCH v3] " Johannes Sixt
2008-08-27  3:18                   ` [PATCH v2] Support "core.excludesfile = ~/.gitignore" Karl Chen
2008-08-27  4:50                     ` Junio C Hamano
2009-11-18  7:29 [PATCH v3] Expand ~ and ~user in core.excludesfile, commit.template Matthieu Moy
2009-11-18  8:58 ` [PATCH v4] " Matthieu Moy
2009-11-19 18:12   ` Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).