Skip to content

Commit 2374faa

Browse files
committed
patch 8.0.1469: when package path is a symlink 'runtimepath' is wrong
Problem: When package path is a symlink adding it to 'runtimepath' happens at the end. Solution: Do not resolve symlinks before locating the position in 'runtimepath'. (Ozaki Kiichi, closes #2604)
1 parent 191f18b commit 2374faa

3 files changed

Lines changed: 178 additions & 112 deletions

File tree

src/ex_cmds2.c

Lines changed: 132 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -3567,13 +3567,11 @@ source_all_matches(char_u *pat)
35673567
}
35683568
}
35693569

3570-
/* used for "cookie" of add_pack_plugin() */
3571-
static int APP_ADD_DIR;
3572-
static int APP_LOAD;
3573-
static int APP_BOTH;
3574-
3575-
static void
3576-
add_pack_plugin(char_u *fname, void *cookie)
3570+
/*
3571+
* Add the package directory to 'runtimepath'.
3572+
*/
3573+
static int
3574+
add_pack_dir_to_rtp(char_u *fname)
35773575
{
35783576
char_u *p4, *p3, *p2, *p1, *p;
35793577
char_u *insp;
@@ -3582,125 +3580,154 @@ add_pack_plugin(char_u *fname, void *cookie)
35823580
int keep;
35833581
size_t oldlen;
35843582
size_t addlen;
3585-
char_u *afterdir;
3583+
char_u *afterdir = NULL;
35863584
size_t afterlen = 0;
3587-
char_u *ffname = fix_fname(fname);
3585+
char_u *ffname = NULL;
35883586
size_t fname_len;
35893587
char_u *buf = NULL;
35903588
char_u *rtp_ffname;
35913589
int match;
3590+
int retval = FAIL;
35923591

3593-
if (ffname == NULL)
3594-
return;
3595-
if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
3596-
{
3597-
/* directory is not yet in 'runtimepath', add it */
3598-
p4 = p3 = p2 = p1 = get_past_head(ffname);
3599-
for (p = p1; *p; MB_PTR_ADV(p))
3600-
if (vim_ispathsep_nocolon(*p))
3601-
{
3602-
p4 = p3; p3 = p2; p2 = p1; p1 = p;
3603-
}
3604-
3605-
/* now we have:
3606-
* rtp/pack/name/start/name
3607-
* p4 p3 p2 p1
3608-
*
3609-
* find the part up to "pack" in 'runtimepath' */
3610-
c = *p4;
3611-
*p4 = NUL;
3612-
3613-
/* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3614-
fname_len = STRLEN(ffname);
3615-
insp = p_rtp;
3616-
buf = alloc(MAXPATHL);
3617-
if (buf == NULL)
3618-
goto theend;
3619-
while (*insp != NUL)
3592+
p4 = p3 = p2 = p1 = get_past_head(fname);
3593+
for (p = p1; *p; MB_PTR_ADV(p))
3594+
if (vim_ispathsep_nocolon(*p))
36203595
{
3621-
copy_option_part(&insp, buf, MAXPATHL, ",");
3622-
add_pathsep(buf);
3623-
rtp_ffname = fix_fname(buf);
3624-
if (rtp_ffname == NULL)
3625-
goto theend;
3626-
match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
3627-
vim_free(rtp_ffname);
3628-
if (match)
3629-
break;
3596+
p4 = p3; p3 = p2; p2 = p1; p1 = p;
36303597
}
36313598

3632-
if (*insp == NUL)
3633-
/* not found, append at the end */
3634-
insp = p_rtp + STRLEN(p_rtp);
3635-
else
3636-
/* append after the matching directory. */
3637-
--insp;
3638-
*p4 = c;
3639-
3640-
/* check if rtp/pack/name/start/name/after exists */
3641-
afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3642-
if (afterdir != NULL && mch_isdir(afterdir))
3643-
afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3644-
3645-
oldlen = STRLEN(p_rtp);
3646-
addlen = STRLEN(ffname) + 1; /* add one for comma */
3647-
new_rtp = alloc((int)(oldlen + addlen + afterlen + 1));
3648-
/* add one for NUL */
3649-
if (new_rtp == NULL)
3599+
/* now we have:
3600+
* rtp/pack/name/start/name
3601+
* p4 p3 p2 p1
3602+
*
3603+
* find the part up to "pack" in 'runtimepath' */
3604+
c = *++p4; /* append pathsep in order to expand symlink */
3605+
*p4 = NUL;
3606+
ffname = fix_fname(fname);
3607+
*p4 = c;
3608+
if (ffname == NULL)
3609+
return FAIL;
3610+
3611+
/* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3612+
fname_len = STRLEN(ffname);
3613+
insp = p_rtp;
3614+
buf = alloc(MAXPATHL);
3615+
if (buf == NULL)
3616+
goto theend;
3617+
while (*insp != NUL)
3618+
{
3619+
copy_option_part(&insp, buf, MAXPATHL, ",");
3620+
add_pathsep(buf);
3621+
rtp_ffname = fix_fname(buf);
3622+
if (rtp_ffname == NULL)
36503623
goto theend;
3651-
keep = (int)(insp - p_rtp);
3652-
mch_memmove(new_rtp, p_rtp, keep);
3653-
new_rtp[keep] = ',';
3654-
mch_memmove(new_rtp + keep + 1, ffname, addlen);
3655-
if (p_rtp[keep] != NUL)
3656-
mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
3657-
oldlen - keep + 1);
3658-
if (afterlen > 0)
3659-
{
3660-
STRCAT(new_rtp, ",");
3661-
STRCAT(new_rtp, afterdir);
3662-
}
3663-
set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3664-
vim_free(new_rtp);
3665-
vim_free(afterdir);
3624+
match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
3625+
vim_free(rtp_ffname);
3626+
if (match)
3627+
break;
36663628
}
36673629

3668-
if (cookie != &APP_ADD_DIR)
3669-
{
3670-
static char *plugpat = "%s/plugin/**/*.vim";
3671-
static char *ftpat = "%s/ftdetect/*.vim";
3672-
int len;
3673-
char_u *pat;
3630+
if (*insp == NUL)
3631+
/* not found, append at the end */
3632+
insp = p_rtp + STRLEN(p_rtp);
3633+
else
3634+
/* append after the matching directory. */
3635+
--insp;
3636+
3637+
/* check if rtp/pack/name/start/name/after exists */
3638+
afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
3639+
if (afterdir != NULL && mch_isdir(afterdir))
3640+
afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3641+
3642+
oldlen = STRLEN(p_rtp);
3643+
addlen = STRLEN(fname) + 1; /* add one for comma */
3644+
new_rtp = alloc((int)(oldlen + addlen + afterlen + 1));
3645+
/* add one for NUL */
3646+
if (new_rtp == NULL)
3647+
goto theend;
3648+
keep = (int)(insp - p_rtp);
3649+
mch_memmove(new_rtp, p_rtp, keep);
3650+
new_rtp[keep] = ',';
3651+
mch_memmove(new_rtp + keep + 1, fname, addlen);
3652+
if (p_rtp[keep] != NUL)
3653+
mch_memmove(new_rtp + keep + addlen, p_rtp + keep, oldlen - keep + 1);
3654+
if (afterlen > 0)
3655+
{
3656+
STRCAT(new_rtp, ",");
3657+
STRCAT(new_rtp, afterdir);
3658+
}
3659+
set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3660+
vim_free(new_rtp);
3661+
retval = OK;
36743662

3675-
len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3676-
pat = alloc(len);
3677-
if (pat == NULL)
3678-
goto theend;
3679-
vim_snprintf((char *)pat, len, plugpat, ffname);
3680-
source_all_matches(pat);
3663+
theend:
3664+
vim_free(buf);
3665+
vim_free(ffname);
3666+
vim_free(afterdir);
3667+
return retval;
3668+
}
3669+
3670+
/*
3671+
* Load scripts in "plugin" and "ftdetect" directories of the package.
3672+
*/
3673+
static int
3674+
load_pack_plugin(char_u *fname)
3675+
{
3676+
static char *plugpat = "%s/plugin/**/*.vim";
3677+
static char *ftpat = "%s/ftdetect/*.vim";
3678+
int len;
3679+
char_u *ffname = fix_fname(fname);
3680+
char_u *pat = NULL;
3681+
int retval = FAIL;
3682+
3683+
if (ffname == NULL)
3684+
return FAIL;
3685+
len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3686+
pat = alloc(len);
3687+
if (pat == NULL)
3688+
goto theend;
3689+
vim_snprintf((char *)pat, len, plugpat, ffname);
3690+
source_all_matches(pat);
36813691

36823692
#ifdef FEAT_AUTOCMD
3683-
{
3684-
char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3693+
{
3694+
char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
36853695

3686-
/* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3687-
* found when it loads. */
3688-
if (cmd != NULL && eval_to_number(cmd) > 0)
3689-
{
3690-
do_cmdline_cmd((char_u *)"augroup filetypedetect");
3691-
vim_snprintf((char *)pat, len, ftpat, ffname);
3692-
source_all_matches(pat);
3693-
do_cmdline_cmd((char_u *)"augroup END");
3694-
}
3695-
vim_free(cmd);
3696+
/* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3697+
* found when it loads. */
3698+
if (cmd != NULL && eval_to_number(cmd) > 0)
3699+
{
3700+
do_cmdline_cmd((char_u *)"augroup filetypedetect");
3701+
vim_snprintf((char *)pat, len, ftpat, ffname);
3702+
source_all_matches(pat);
3703+
do_cmdline_cmd((char_u *)"augroup END");
36963704
}
3697-
#endif
3698-
vim_free(pat);
3705+
vim_free(cmd);
36993706
}
3707+
#endif
3708+
vim_free(pat);
3709+
retval = OK;
37003710

37013711
theend:
3702-
vim_free(buf);
37033712
vim_free(ffname);
3713+
return retval;
3714+
}
3715+
3716+
/* used for "cookie" of add_pack_plugin() */
3717+
static int APP_ADD_DIR;
3718+
static int APP_LOAD;
3719+
static int APP_BOTH;
3720+
3721+
static void
3722+
add_pack_plugin(char_u *fname, void *cookie)
3723+
{
3724+
if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)fname) == NULL)
3725+
/* directory is not yet in 'runtimepath', add it */
3726+
if (add_pack_dir_to_rtp(fname) == FAIL)
3727+
return;
3728+
3729+
if (cookie != &APP_ADD_DIR)
3730+
load_pack_plugin(fname);
37043731
}
37053732

37063733
/*

src/testdir/test_packadd.vim

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ func Test_packadd()
3737
call assert_equal(77, g:plugin_also_works)
3838
call assert_equal(17, g:ftdetect_works)
3939
call assert_true(len(&rtp) > len(rtp))
40-
call assert_true(&rtp =~ '/testdir/Xdir/pack/mine/opt/mytest\($\|,\)')
41-
call assert_true(&rtp =~ '/testdir/Xdir/pack/mine/opt/mytest/after$')
40+
call assert_match('/testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp)
41+
call assert_match('/testdir/Xdir/pack/mine/opt/mytest/after$', &rtp)
4242

4343
" Check exception
4444
call assert_fails("packadd directorynotfound", 'E919:')
@@ -60,7 +60,7 @@ func Test_packadd_start()
6060

6161
call assert_equal(24, g:plugin_works)
6262
call assert_true(len(&rtp) > len(rtp))
63-
call assert_true(&rtp =~ '/testdir/Xdir/pack/mine/start/other\($\|,\)')
63+
call assert_match('/testdir/Xdir/pack/mine/start/other\($\|,\)', &rtp)
6464
endfunc
6565

6666
func Test_packadd_noload()
@@ -77,7 +77,7 @@ func Test_packadd_noload()
7777
packadd! mytest
7878

7979
call assert_true(len(&rtp) > len(rtp))
80-
call assert_true(&rtp =~ 'testdir/Xdir/pack/mine/opt/mytest\($\|,\)')
80+
call assert_match('testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp)
8181
call assert_equal(0, g:plugin_works)
8282

8383
" check the path is not added twice
@@ -108,7 +108,7 @@ func Test_packadd_symlink_dir()
108108
packadd mytest
109109

110110
" Must have been inserted in the middle, not at the end
111-
call assert_true(&rtp =~ '/pack/mine/opt/mytest,')
111+
call assert_match('/pack/mine/opt/mytest,', &rtp)
112112
call assert_equal(44, g:plugin_works)
113113

114114
" No change when doing it again.
@@ -121,6 +121,43 @@ func Test_packadd_symlink_dir()
121121
exec "silent !rm" top2_dir
122122
endfunc
123123

124+
func Test_packadd_symlink_dir2()
125+
if !has('unix')
126+
return
127+
endif
128+
let top2_dir = s:topdir . '/Xdir2'
129+
let real_dir = s:topdir . '/Xsym/pack'
130+
call mkdir(top2_dir, 'p')
131+
call mkdir(real_dir, 'p')
132+
let &rtp = top2_dir . ',' . top2_dir . '/after'
133+
let &packpath = &rtp
134+
135+
exec "silent !ln -s ../Xsym/pack" top2_dir . '/pack'
136+
let s:plugdir = top2_dir . '/pack/mine/opt/mytest'
137+
call mkdir(s:plugdir . '/plugin', 'p')
138+
139+
exe 'split ' . s:plugdir . '/plugin/test.vim'
140+
call setline(1, 'let g:plugin_works = 48')
141+
wq
142+
let g:plugin_works = 0
143+
144+
packadd mytest
145+
146+
" Must have been inserted in the middle, not at the end
147+
call assert_match('/Xdir2/pack/mine/opt/mytest,', &rtp)
148+
call assert_equal(48, g:plugin_works)
149+
150+
" No change when doing it again.
151+
let rtp_before = &rtp
152+
packadd mytest
153+
call assert_equal(rtp_before, &rtp)
154+
155+
set rtp&
156+
let rtp = &rtp
157+
exec "silent !rm" top2_dir . '/pack'
158+
exec "silent !rmdir" top2_dir
159+
endfunc
160+
124161
" Check command-line completion for 'packadd'
125162
func Test_packadd_completion()
126163
let optdir1 = &packpath . '/pack/mine/opt'
@@ -196,9 +233,9 @@ func Test_helptags()
196233
helptags ALL
197234

198235
let tags1 = readfile(docdir1 . '/tags')
199-
call assert_true(tags1[0] =~ 'look-here')
236+
call assert_match('look-here', tags1[0])
200237
let tags2 = readfile(docdir2 . '/tags')
201-
call assert_true(tags2[0] =~ 'look-away')
238+
call assert_match('look-away', tags2[0])
202239
endfunc
203240

204241
func Test_colorscheme()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ static char *(features[]) =
771771

772772
static int included_patches[] =
773773
{ /* Add new patch number below this line */
774+
/**/
775+
1469,
774776
/**/
775777
1468,
776778
/**/

0 commit comments

Comments
 (0)