Skip to content

Commit 0cbee9b

Browse files
convert: add alias support for 'working-tree-encoding' attributes
In 107642f ("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@gmail.com>
1 parent c5a19f6 commit 0cbee9b

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

Documentation/gitattributes.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,25 @@ command to guess the encoding:
366366
file foo.ps1
367367
------------------------
368368

369+
The encoding in all examples above was directly defined in the Git
370+
attributes. In addition, it is possible to define encodings indirectly
371+
using aliases set via Git config:
372+
373+
------------------------
374+
[encoding "UTF-16"]
375+
insteadOf = my-custom-alias
376+
------------------------
377+
378+
The alias name can be used in the Git attributes instead of the actual
379+
encoding name:
380+
381+
------------------------
382+
*.ps1 text working-tree-encoding=my-custom-alias
383+
------------------------
384+
385+
This mapping can be useful if equivalent encodings are spelled
386+
differently across platforms. It can also be useful if a user wants to
387+
use different encodings on different platforms for the same file.
369388

370389
`ident`
371390
^^^^^^^

convert.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,15 @@ static int apply_filter(const char *path, const char *src, size_t len,
997997
return 0;
998998
}
999999

1000+
struct alias2enc {
1001+
struct hashmap_entry ent; /* must be the first member! */
1002+
const char *alias;
1003+
const char *encoding;
1004+
};
1005+
1006+
static int encoding_aliases_initialized;
1007+
static struct hashmap encoding_map;
1008+
10001009
static int read_convert_config(const char *var, const char *value, void *cb)
10011010
{
10021011
const char *key, *name;
@@ -1040,6 +1049,36 @@ static int read_convert_config(const char *var, const char *value, void *cb)
10401049
drv->required = git_config_bool(var, value);
10411050
return 0;
10421051
}
1052+
} else if (
1053+
parse_config_key(var, "encoding", &name, &namelen, &key) >= 0 &&
1054+
name && !strcmp(key, "insteadof")) {
1055+
/*
1056+
* Encoding aliases are configured using
1057+
* "encoding.<iconv-name>.insteadOf = <alias-name>".
1058+
*/
1059+
struct alias2enc *entry;
1060+
if (!value)
1061+
return config_error_nonbool(key);
1062+
1063+
if (!encoding_aliases_initialized) {
1064+
encoding_aliases_initialized = 1;
1065+
hashmap_init(&encoding_map, NULL, NULL, 0);
1066+
entry = NULL;
1067+
} else {
1068+
struct alias2enc hashkey;
1069+
hashmap_entry_init(&hashkey, strihash(value));
1070+
hashkey.alias = value;
1071+
entry = hashmap_get(&encoding_map, &hashkey, NULL);
1072+
}
1073+
1074+
if (!entry) {
1075+
entry = xmalloc(sizeof(*entry));
1076+
entry->encoding = xstrndup(name, namelen);
1077+
entry->alias = xstrdup(value);
1078+
1079+
hashmap_entry_init(entry, strihash(value));
1080+
hashmap_add(&encoding_map, entry);
1081+
}
10431082
}
10441083

10451084
return 0;
@@ -1225,6 +1264,17 @@ static const char *git_path_check_encoding(struct attr_check_item *check)
12251264
die(_("true/false are no valid working-tree-encodings"));
12261265
}
12271266

1267+
/* Check if an alias was defined for the encoding in the Git config */
1268+
if (encoding_aliases_initialized) {
1269+
struct alias2enc hashkey;
1270+
struct alias2enc *entry;
1271+
hashmap_entry_init(&hashkey, strihash(value));
1272+
hashkey.alias = value;
1273+
entry = hashmap_get(&encoding_map, &hashkey, NULL);
1274+
if (entry)
1275+
value = entry->encoding;
1276+
}
1277+
12281278
/* Don't encode to the default encoding */
12291279
if (same_encoding(value, default_encoding))
12301280
return NULL;

t/t0028-working-tree-encoding.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,32 @@ test_expect_success 'check roundtrip encoding' '
242242
git reset
243243
'
244244

245+
test_expect_success 'encoding alias' '
246+
test_when_finished "rm -f test.foo16.git test.foo8" &&
247+
test_when_finished "git reset --hard HEAD" &&
248+
249+
test_config encoding.UTF-16.InsteadOf foo16 &&
250+
251+
text="hallo there!\ncan you read me with an alias?" &&
252+
printf "$text" >test.foo8 &&
253+
printf "$text" | iconv -f UTF-8 -t UTF-16 >test.foo16 &&
254+
255+
echo "*.foo16 text working-tree-encoding=fOO16" >.gitattributes &&
256+
git add test.foo16 .gitattributes &&
257+
258+
git cat-file -p :test.foo16 >test.foo16.git &&
259+
test_cmp_bin test.foo8 test.foo16.git
260+
'
261+
262+
test_expect_success 'encoding alias overwrites existing encoding' '
263+
test_when_finished "git reset --hard HEAD" &&
264+
265+
test_config encoding.CONFUSE.insteadOf UTF-16 &&
266+
267+
echo "*.garbage text working-tree-encoding=UTF-16" >.gitattributes &&
268+
printf "garbage" >t.garbage &&
269+
test_must_fail git add t.garbage 2>err.out &&
270+
test_i18ngrep "failed to encode .* from CONFUSE to UTF-8" err.out
271+
'
272+
245273
test_done

0 commit comments

Comments
 (0)