From: Lars Schneider <larsxschneider@xxxxxxxxx> In 107642fe26 ("convert: add 'working-tree-encoding' attribute", 2018-04-15) we added an attribute which defines the working tree encoding of a file. Some platforms might spell the name of a certain encoding differently or some users might want to use different encodings on different platforms. Add the Git config "encoding.<iconv-name>.insteadOf = <alias-name>" to support these use-cases with a user specific mapping. If the alias matches an existing encoding name, then the alias will take precedence. The alias is case insensitive. Example: (in .gitattributes) *.c working-tree-encoding=foo (in config) [encoding "UTF-16"] insteadOf = foo Signed-off-by: Lars Schneider <larsxschneider@xxxxxxxxx> --- Documentation/gitattributes.txt | 19 ++++++++++++ convert.c | 50 ++++++++++++++++++++++++++++++++ t/t0028-working-tree-encoding.sh | 28 ++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 92010b062e..3628f0e5cf 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -366,6 +366,25 @@ command to guess the encoding: file foo.ps1 ------------------------ +The encoding in all examples above was directly defined in the Git +attributes. In addition, it is possible to define encodings indirectly +using aliases set via Git config: + +------------------------ +[encoding "UTF-16"] + insteadOf = my-custom-alias +------------------------ + +The alias name can be used in the Git attributes instead of the actual +encoding name: + +------------------------ +*.ps1 text working-tree-encoding=my-custom-alias +------------------------ + +This mapping can be useful if equivalent encodings are spelled +differently across platforms. It can also be useful if a user wants to +use different encodings on different platforms for the same file. `ident` ^^^^^^^ diff --git a/convert.c b/convert.c index 949bc783e4..4f19ce1a04 100644 --- a/convert.c +++ b/convert.c @@ -997,6 +997,15 @@ static int apply_filter(const char *path, const char *src, size_t len, return 0; } +struct alias2enc { + struct hashmap_entry ent; /* must be the first member! */ + const char *alias; + const char *encoding; +}; + +static int encoding_aliases_initialized; +static struct hashmap encoding_map; + static int read_convert_config(const char *var, const char *value, void *cb) { const char *key, *name; @@ -1040,6 +1049,36 @@ static int read_convert_config(const char *var, const char *value, void *cb) drv->required = git_config_bool(var, value); return 0; } + } else if ( + parse_config_key(var, "encoding", &name, &namelen, &key) >= 0 && + name && !strcmp(key, "insteadof")) { + /* + * Encoding aliases are configured using + * "encoding.<iconv-name>.insteadOf = <alias-name>". + */ + struct alias2enc *entry; + if (!value) + return config_error_nonbool(key); + + if (!encoding_aliases_initialized) { + encoding_aliases_initialized = 1; + hashmap_init(&encoding_map, NULL, NULL, 0); + entry = NULL; + } else { + struct alias2enc hashkey; + hashmap_entry_init(&hashkey, strihash(value)); + hashkey.alias = value; + entry = hashmap_get(&encoding_map, &hashkey, NULL); + } + + if (!entry) { + entry = xmalloc(sizeof(*entry)); + entry->encoding = xstrndup(name, namelen); + entry->alias = xstrdup(value); + + hashmap_entry_init(entry, strihash(value)); + hashmap_add(&encoding_map, entry); + } } return 0; @@ -1225,6 +1264,17 @@ static const char *git_path_check_encoding(struct attr_check_item *check) die(_("true/false are no valid working-tree-encodings")); } + /* Check if an alias was defined for the encoding in the Git config */ + if (encoding_aliases_initialized) { + struct alias2enc hashkey; + struct alias2enc *entry; + hashmap_entry_init(&hashkey, strihash(value)); + hashkey.alias = value; + entry = hashmap_get(&encoding_map, &hashkey, NULL); + if (entry) + value = entry->encoding; + } + /* Don't encode to the default encoding */ if (same_encoding(value, default_encoding)) return NULL; diff --git a/t/t0028-working-tree-encoding.sh b/t/t0028-working-tree-encoding.sh index 12b8eb963a..d803e00cbe 100755 --- a/t/t0028-working-tree-encoding.sh +++ b/t/t0028-working-tree-encoding.sh @@ -242,4 +242,32 @@ test_expect_success 'check roundtrip encoding' ' git reset ' +test_expect_success 'encoding alias' ' + test_when_finished "rm -f test.foo16.git test.foo8" && + test_when_finished "git reset --hard HEAD" && + + test_config encoding.UTF-16.InsteadOf foo16 && + + text="hallo there!\ncan you read me with an alias?" && + printf "$text" >test.foo8 && + printf "$text" | iconv -f UTF-8 -t UTF-16 >test.foo16 && + + echo "*.foo16 text working-tree-encoding=fOO16" >.gitattributes && + git add test.foo16 .gitattributes && + + git cat-file -p :test.foo16 >test.foo16.git && + test_cmp_bin test.foo8 test.foo16.git +' + +test_expect_success 'encoding alias overwrites existing encoding' ' + test_when_finished "git reset --hard HEAD" && + + test_config encoding.CONFUSE.insteadOf UTF-16 && + + echo "*.garbage text working-tree-encoding=UTF-16" >.gitattributes && + printf "garbage" >t.garbage && + test_must_fail git add t.garbage 2>err.out && + test_i18ngrep "failed to encode .* from CONFUSE to UTF-8" err.out +' + test_done -- 2.18.0