Guest
Public paste!

goobsoft

By: a guest | Oct 21st, 2007 | Syntax: Python | Size: 15.91 KB | Hits: 167 | Expires: Never
This paste has a previous version, view the difference. Copy text to clipboard
  1. qpush asserts that patches do not affect unknown files
  2. * * *
  3.  
  4. diff --git a/hgext/mq.py b/hgext/mq.py
  5. --- a/hgext/mq.py
  6. +++ b/hgext/mq.py
  7.  -599,6 +599,31 @@ class queue:
  8.                  else:
  9.                      raise util.Abort(_("local changes found"))
  10.          return m, a, r, d
  11. +
  12. +    def get_unknown(self, repo, affectedfiles):
  13. +        unknownfiles = set([])
  14. +        for f in affectedfiles:
  15. +            if util.lexists(repo.wjoin(f)):
  16. +                if f not in repo.dirstate:
  17. +                      unknownfiles.add(f)
  18. +        return unknownfiles
  19. +
  20. +    def check_unknown(self, repo, patchname, patchdir=None):
  21. +        if not patchdir:
  22. +            patchdir = self.path
  23. +
  24. +        patchpath = os.path.join(patchdir, patchname)
  25. +
  26. +        affectedfiles = patch.getaffected(patchpath, self.ui, strip=1)
  27. +        if len(affectedfiles) == 0:
  28. +            if os.stat(patchpath).st_size > 0:
  29. +                self.ui.warn(_('Could not detect files that will be affected by %s.  Can not assure that files are added and committed.\n') % patchname)
  30. +                # or could force check of all files unless Force is true or something like that...
  31. +        
  32. +        unknownfiles = self.get_unknown(repo, affectedfiles)
  33. +        if len(unknownfiles) > 0:
  34. +            raise util.Abort(_('Patch %s can not be applied.  Patch effects unknown files %s') % (patchname, unknownfiles))
  35. +
  36.  
  37.      def new(self, repo, patch, *pats, **opts):
  38.          msg = opts.get('msg')
  39.  -781,6 +806,11 @@ class queue:
  40.              else:
  41.                  end = self.series.index(patch, start) + 1
  42.              s = self.series[start:end]
  43. +
  44. +            if not force:
  45. +                for patchname in s:
  46. +                    self.check_unknown(repo, patchname);
  47. +
  48.              all_files = {}
  49.              try:
  50.                  if mergeq:
  51. diff --git a/mercurial/patch.py b/mercurial/patch.py
  52. --- a/mercurial/patch.py
  53. +++ b/mercurial/patch.py
  54.  -496,6 +496,50 @@ class patchfile:
  55.          self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
  56.          self.rej.append(h)
  57.          return -1
  58. +
  59. +def getaffected(patchfilepath, ui, strip=1):
  60. +    lsdiff = ui.config('ui', 'lsdiff')
  61. +    if lsdiff:
  62. +        return externalgetaffected(lsdiff, patchfilepath, strip);
  63. +    else:
  64. +        return internalgetaffected(patchfilepath, strip);
  65. +
  66. +
  67. +def externalgetaffected(lsdiff, patchfilepath, strip=1):
  68. +    fp = os.popen('%s %s' % (lsdiff, util.shellquote(patchfilepath)))
  69. +    files = []
  70. +
  71. +    for line in fp:
  72. +        affectedfile = line.strip()
  73. +        files.append(pathstrip(affectedfile, strip))
  74. +    code = fp.close()
  75. +    if code:
  76. +        raise PatchError(_("lsdiff command failed: %s") %
  77. +                         util.explain_exit(code)[0])
  78. +    return files;
  79. +
  80. +
  81. +def internalgetaffected(patchfilepath, strip=1):
  82. +    files = set()
  83. +    difftag = re.compile("^diff( --?[^\\s]*)* a/.* (b/.*)$") # doesn't handle c-style quotes
  84. +    orig_pattern = re.compile("^((\\*{3})|(\\-{3}))\\s") # *** or +++
  85. +    new_pattern = re.compile("^((\\-{3})|(\\+{3}))\\s([^\\t]*)")
  86. +    found_orig=False;
  87. +    for line in file(patchfilepath):
  88. +        diffmatcher = difftag.match(line)
  89. +        if diffmatcher != None:
  90. +            files.add(pathstrip(diffmatcher.group(2), strip))
  91. +
  92. +        if not found_orig:
  93. +            matcher = orig_pattern.match(line);
  94. +            if matcher != None:
  95. +                found_orig=True
  96. +        else:
  97. +            found_orig=False
  98. +            matcher = new_pattern.match(line)
  99. +            if matcher != None:
  100. +                files.add(pathstrip(matcher.group(4), strip))
  101. +    return files
  102.  
  103.  class hunk:
  104.      def __init__(self, desc, num, lr, context):
  105.  -774,24 +818,24 @@ def parsefilename(str):
  106.              return s
  107.      return s[:i]
  108.  
  109. +def pathstrip(path, count=1):
  110. +    pathlen = len(path)
  111. +    i = 0
  112. +    if count == 0:
  113. +        return path.rstrip()
  114. +    while count > 0:
  115. +        i = path.find('/', i)
  116. +        if i == -1:
  117. +            raise PatchError(_("unable to strip away %d dirs from %s") %
  118. +                             (count, path))
  119. +        i += 1
  120. +        # consume '//' in the path
  121. +        while i < pathlen - 1 and path[i] == '/':
  122. +            i += 1
  123. +        count -= 1
  124. +    return path[i:].rstrip()
  125. +
  126.  def selectfile(afile_orig, bfile_orig, hunk, strip, reverse):
  127. -    def pathstrip(path, count=1):
  128. -        pathlen = len(path)
  129. -        i = 0
  130. -        if count == 0:
  131. -            return path.rstrip()
  132. -        while count > 0:
  133. -            i = path.find('/', i)
  134. -            if i == -1:
  135. -                raise PatchError(_("unable to strip away %d dirs from %s") %
  136. -                                 (count, path))
  137. -            i += 1
  138. -            # consume '//' in the path
  139. -            while i < pathlen - 1 and path[i] == '/':
  140. -                i += 1
  141. -            count -= 1
  142. -        return path[i:].rstrip()
  143. -
  144.      nulla = afile_orig == "/dev/null"
  145.      nullb = bfile_orig == "/dev/null"
  146.      afile = pathstrip(afile_orig, strip)
  147. diff --git a/tests/test-mq-qpush-error b/tests/test-mq-qpush-error
  148. new file mode 100755
  149. --- /dev/null
  150. +++ b/tests/test-mq-qpush-error
  151.  -0,0 +1,21 @@
  152. +#!/bin/bash
  153. +
  154. +echo "[extensions]" >> $HGRCPATH
  155. +echo "mq=" >> $HGRCPATH
  156. +
  157. +mkdir tmp1
  158. +mkdir tmp2
  159. +
  160. +echo hi >> tmp1/foo
  161. +echo h2 >> tmp2/foo
  162. +
  163. +diff -uNr tmp1 tmp2 > unified.patch
  164. +
  165. +cd tmp1
  166. +hg init
  167. +hg qinit
  168. +hg qimport ../unified.patch
  169. +hg qpush
  170. +hg qpop
  171. +#ls: foo: No such file or directory
  172. +ls -1 foo
  173. diff --git a/tests/test-mq-qpush-error.out b/tests/test-mq-qpush-error.out
  174. new file mode 100644
  175. --- /dev/null
  176. +++ b/tests/test-mq-qpush-error.out
  177.  -0,0 +1,4 @@
  178. +adding unified.patch to series file
  179. +abort: Patch unified.patch can not be applied.  Patch effects unknown files set(['foo'])
  180. +no patches applied
  181. +foo
  182. diff --git a/tests/test-mq-qpush-unknown b/tests/test-mq-qpush-unknown
  183. new file mode 100755
  184. --- /dev/null
  185. +++ b/tests/test-mq-qpush-unknown
  186.  -0,0 +1,229 @@
  187. +#!/bin/bash
  188. +
  189. +echo "[extensions]" >> $HGRCPATH
  190. +echo "mq=" >> $HGRCPATH
  191. +
  192. +mkdir tmp1
  193. +mkdir tmp1/dir
  194. +mkdir tmp2
  195. +mkdir tmp2/dir
  196. +
  197. +echo hi >> tmp1/foo
  198. +echo hi >> tmp1/foo
  199. +echo hi >> tmp1/foo
  200. +echo hi >> tmp1/foo
  201. +
  202. +echo hi >> tmp1/dir/bar
  203. +echo hi >> tmp1/dir/bar
  204. +echo hi >> tmp1/dir/bar
  205. +echo hi >> tmp1/dir/bar
  206. +
  207. +echo hi >> tmp2/foo
  208. +echo h2 >> tmp2/foo
  209. +echo hi >> tmp2/foo
  210. +echo h4 >> tmp2/foo
  211. +
  212. +echo hi >> tmp2/dir/bar
  213. +echo hi >> tmp2/dir/bar
  214. +echo h3 >> tmp2/dir/bar
  215. +echo hi >> tmp2/dir/bar
  216. +
  217. +diff -uNr tmp1 tmp2 > unified.patch
  218. +diff -eNr tmp1 tmp2 > ed.patch
  219. +diff -nNr tmp1 tmp2 > normal.patch
  220. +diff -cNr tmp1 tmp2 > context.patch
  221. +
  222. +# don't want to require git just to support.  Pregenerated.
  223. +cat > git.patch <<EOF
  224. +diff --git a/dir/bar b/dir/bar
  225. +index af8b2b3..49a5f2f 100644
  226. +--- a/dir/bar
  227. ++++ b/dir/bar
  228. +@@ -1,4 +1,4 @@
  229. + hi
  230. + hi
  231. +-hi
  232. ++h3
  233. + hi
  234. +diff --git a/foo b/foo
  235. +index af8b2b3..8953a92 100644
  236. +--- a/foo
  237. ++++ b/foo
  238. +@@ -1,4 +1,4 @@
  239. + hi
  240. ++h2
  241. + hi
  242. +-hi
  243. +-hi
  244. ++h4
  245. +EOF
  246. +
  247. +echo % qpush unknown correct
  248. +cp -r tmp1 tmp3
  249. +cd tmp3
  250. +hg init
  251. +hg add
  252. +hg commit -m "test"
  253. +hg qinit
  254. +hg qimport ../unified.patch
  255. +hg qpush
  256. +cat foo | grep h2
  257. +cat dir/bar | grep h3
  258. +hg qpop
  259. +cat foo | grep hi | wc -l
  260. +cat dir/bar | grep hi | wc -l
  261. +cd ..
  262. +rm -rf tmp3
  263. +
  264. +echo % qpush unknown correct 2
  265. +cp -r tmp1 tmp3
  266. +cd tmp3
  267. +hg init
  268. +hg add
  269. +hg commit -m "test"
  270. +hg qinit
  271. +hg qimport ../context.patch
  272. +hg qpush
  273. +cat foo | grep h2
  274. +cat dir/bar | grep h3
  275. +hg qpop
  276. +cat foo | grep hi | wc -l
  277. +cat dir/bar | grep hi | wc -l
  278. +cd ..
  279. +rm -rf tmp3
  280. +
  281. +echo % qpush unknown correct 3
  282. +cp -r tmp1 tmp3
  283. +cd tmp3
  284. +hg init
  285. +hg add
  286. +hg commit -m "test"
  287. +hg qinit
  288. +hg qimport ../git.patch
  289. +hg qpush
  290. +cat foo | grep h2
  291. +cat dir/bar | grep h3
  292. +hg qpop
  293. +cat foo | grep hi | wc -l
  294. +cat dir/bar | grep hi | wc -l
  295. +cd ..
  296. +rm -rf tmp3
  297. +
  298. +echo % qpush unknown correct 4 - qpush from sub directory
  299. +cp -r tmp1 tmp3
  300. +cd tmp3
  301. +hg init
  302. +hg add
  303. +hg commit -m "test"
  304. +hg qinit
  305. +hg qimport ../git.patch
  306. +cd dir
  307. +hg qpush
  308. +cd ..
  309. +cat foo | grep h2
  310. +cat dir/bar | grep h3
  311. +hg qpop
  312. +cat foo | grep hi | wc -l
  313. +cat dir/bar | grep hi | wc -l
  314. +cd ..
  315. +rm -rf tmp3
  316. +
  317. +echo % qpush unknown warn
  318. +cp -r tmp1 tmp3
  319. +cd tmp3
  320. +hg init
  321. +hg add
  322. +hg commit -m "test"
  323. +hg qinit
  324. +hg qimport ../ed.patch
  325. +hg qpush
  326. +cd ..
  327. +rm -rf tmp3
  328. +
  329. +echo % qpush unknown warn 2
  330. +cp -r tmp1 tmp3
  331. +cd tmp3
  332. +hg init
  333. +hg add
  334. +hg commit -m "test"
  335. +hg qinit
  336. +hg qimport ../normal.patch
  337. +hg qpush
  338. +cd ..
  339. +rm -rf tmp3
  340. +
  341. +echo % qpush unknown error
  342. +cp -r tmp1 tmp3
  343. +cd tmp3
  344. +hg init
  345. +hg add foo # but not bar
  346. +hg qinit
  347. +hg qimport ../unified.patch
  348. +hg qpush
  349. +cd ..
  350. +rm -rf tmp3
  351. +
  352. +echo % qpush unknown error 2
  353. +cp -r tmp1 tmp3
  354. +cd tmp3
  355. +hg init
  356. +hg add dir/bar # but not foo
  357. +hg qinit
  358. +hg qimport ../context.patch
  359. +hg qpush
  360. +cd ..
  361. +rm -rf tmp3
  362. +
  363. +echo % qpush unknown error 3
  364. +cp -r tmp1 tmp3
  365. +cd tmp3
  366. +hg init
  367. +# add nothing
  368. +hg qinit
  369. +hg qimport ../git.patch
  370. +hg qpush
  371. +cd ..
  372. +rm -rf tmp3
  373. +
  374. +
  375. +echo % create bgit.patch
  376. +
  377. +cp -rp tmp1 tmp3
  378. +cd tmp3
  379. +hg init
  380. +hg qinit
  381. +hg qnew binary
  382. +
  383. +cat > writebin.py <<EOF
  384. +import sys
  385. +open('binaryfile', 'wb').write('BIN\x00ARY')
  386. +EOF
  387. +python writebin.py
  388. +hg add binaryfile
  389. +hg qref --git
  390. +cp .hg/patches/binary ../bgit.patch
  391. +cd ..
  392. +rm -r tmp3
  393. +
  394. +echo % bgit.patch works
  395. +
  396. +cp -rp tmp1 tmp3
  397. +cd tmp3
  398. +hg init
  399. +hg qinit
  400. +hg qimport ../bgit.patch
  401. +hg qpush
  402. +cd ..
  403. +rm -rf tmp3
  404. +
  405. +echo % bgit.patch unknown
  406. +
  407. +cp -rp tmp1 tmp3
  408. +cd tmp3
  409. +hg init
  410. +hg qinit
  411. +echo hi > binaryfile
  412. +hg qimport ../bgit.patch
  413. +hg qpush
  414. +cd ..
  415. +rm -rf tmp3
  416. diff --git a/tests/test-mq-qpush-unknown.out b/tests/test-mq-qpush-unknown.out
  417. new file mode 100644
  418. --- /dev/null
  419. +++ b/tests/test-mq-qpush-unknown.out
  420.  -0,0 +1,80 @@
  421. +% qpush unknown correct
  422. +adding dir/bar
  423. +adding foo
  424. +adding unified.patch to series file
  425. +applying unified.patch
  426. +Now at: unified.patch
  427. +h2
  428. +h3
  429. +Patch queue now empty
  430. +4
  431. +4
  432. +% qpush unknown correct 2
  433. +adding dir/bar
  434. +adding foo
  435. +adding context.patch to series file
  436. +applying context.patch
  437. +Now at: context.patch
  438. +h2
  439. +h3
  440. +Patch queue now empty
  441. +4
  442. +4
  443. +% qpush unknown correct 3
  444. +adding dir/bar
  445. +adding foo
  446. +adding git.patch to series file
  447. +applying git.patch
  448. +Now at: git.patch
  449. +h2
  450. +h3
  451. +Patch queue now empty
  452. +4
  453. +4
  454. +% qpush unknown correct 4 - qpush from sub directory
  455. +adding dir/bar
  456. +adding foo
  457. +adding git.patch to series file
  458. +applying git.patch
  459. +Now at: git.patch
  460. +h2
  461. +h3
  462. +Patch queue now empty
  463. +4
  464. +4
  465. +% qpush unknown warn
  466. +adding dir/bar
  467. +adding foo
  468. +adding ed.patch to series file
  469. +Could not detect files that will be affected by ed.patch.  Can not assure that files are added and committed.
  470. +applying ed.patch
  471. +patch failed, unable to continue (try -v)
  472. +patch ed.patch is empty
  473. +Now at: ed.patch
  474. +% qpush unknown warn 2
  475. +adding dir/bar
  476. +adding foo
  477. +adding normal.patch to series file
  478. +Could not detect files that will be affected by normal.patch.  Can not assure that files are added and committed.
  479. +applying normal.patch
  480. +/usr/bin/patch: **** Only garbage was found in the patch input.
  481. +patch failed, unable to continue (try -v)
  482. +patch normal.patch is empty
  483. +Now at: normal.patch
  484. +% qpush unknown error
  485. +adding unified.patch to series file
  486. +abort: local changes found, refresh first
  487. +% qpush unknown error 2
  488. +adding context.patch to series file
  489. +abort: local changes found, refresh first
  490. +% qpush unknown error 3
  491. +adding git.patch to series file
  492. +abort: Patch git.patch can not be applied.  Patch effects unknown files set(['dir/bar', 'foo'])
  493. +% create bgit.patch
  494. +% bgit.patch works
  495. +adding bgit.patch to series file
  496. +applying bgit.patch
  497. +Now at: bgit.patch
  498. +% bgit.patch unknown
  499. +adding bgit.patch to series file
  500. +abort: Patch bgit.patch can not be applied.  Patch effects unknown files set(['binaryfile'])
  501. diff --git a/tests/test-mq.out b/tests/test-mq.out
  502. --- a/tests/test-mq.out
  503. +++ b/tests/test-mq.out
  504.  -260,19 +260,10 @@ M a
  505.  M a
  506.  % qpush failure
  507.  Patch queue now empty
  508. -applying foo
  509. -applying bar
  510. -file foo already exists
  511. -1 out of 1 hunk FAILED -- saving rejects to file foo.rej
  512. -patch failed, unable to continue (try -v)
  513. -patch failed, rejects left in working dir
  514. -Errors during apply, please fix and refresh bar
  515. +abort: Patch bar can not be applied.  Patch effects unknown files set(['foo'])
  516.  ? foo
  517. -? foo.rej
  518.  % mq tags
  519. -0 qparent
  520. -1 qbase foo
  521. -2 qtip bar tip
  522. +abort: unknown revision 'qparent'!
  523.  new file
  524.  
  525.  diff --git a/new b/new
  526. diff --git a/tests/test-patch-affected b/tests/test-patch-affected
  527. new file mode 100755
  528. --- /dev/null
  529. +++ b/tests/test-patch-affected
  530.  -0,0 +1,81 @@
  531. +#!/bin/bash
  532. +
  533. +mkdir tmp1
  534. +mkdir tmp1/dir
  535. +mkdir tmp2
  536. +mkdir tmp2/dir
  537. +
  538. +echo hi >> tmp1/foo
  539. +echo hi >> tmp1/foo
  540. +echo hi >> tmp1/foo
  541. +echo hi >> tmp1/foo
  542. +
  543. +echo hi >> tmp1/dir/bar
  544. +echo hi >> tmp1/dir/bar
  545. +echo hi >> tmp1/dir/bar
  546. +echo hi >> tmp1/dir/bar
  547. +
  548. +echo hi >> tmp2/foo
  549. +echo h2 >> tmp2/foo
  550. +echo hi >> tmp2/foo
  551. +echo h4 >> tmp2/foo
  552. +
  553. +echo hi >> tmp2/dir/bar
  554. +echo hi >> tmp2/dir/bar
  555. +echo h3 >> tmp2/dir/bar
  556. +echo hi >> tmp2/dir/bar
  557. +
  558. +diff -uNr tmp1 tmp2 > unified.patch
  559. +diff -eNr tmp1 tmp2 > ed.patch
  560. +diff -nNr tmp1 tmp2 > normal.patch
  561. +diff -cNr tmp1 tmp2 > context.patch
  562. +
  563. +# don't want to require git just to support.  Pregenerated.
  564. +cat > git.patch <<EOF
  565. +diff --git a/dir/bar b/dir/bar
  566. +index af8b2b3..49a5f2f 100644
  567. +--- a/dir/bar
  568. ++++ b/dir/bar
  569. +@@ -1,4 +1,4 @@
  570. + hi
  571. + hi
  572. +-hi
  573. ++h3
  574. + hi
  575. +diff --git a/foo b/foo
  576. +index af8b2b3..8953a92 100644
  577. +--- a/foo
  578. ++++ b/foo
  579. +@@ -1,4 +1,4 @@
  580. + hi
  581. ++h2
  582. + hi
  583. +-hi
  584. +-hi
  585. ++h4
  586. +EOF
  587. +
  588. +cat > patch.py <<EOF
  589. +from mercurial import commands, cmdutil, hg, patch, revlog, util
  590. +def printaffected(patchfilepath):
  591. +    files = patch.internalgetaffected(patchfilepath);
  592. +    for f in files:
  593. +        print f;
  594. +
  595. +print("% testing getaffected: unified");
  596. +printaffected("unified.patch");
  597. +
  598. +print("% testing getaffected: ed");
  599. +printaffected("ed.patch");
  600. +
  601. +print("% testing getaffected: normal");
  602. +printaffected("normal.patch");
  603. +
  604. +print("% testing getaffected: context");
  605. +printaffected("context.patch");
  606. +
  607. +print("% testing getaffected: git");
  608. +printaffected("git.patch");
  609. +EOF
  610. +
  611. +python patch.py
  612. diff --git a/tests/test-patch-affected-external b/tests/test-patch-affected-external
  613. new file mode 100755
  614. --- /dev/null
  615. +++ b/tests/test-patch-affected-external
  616.  -0,0 +1,47 @@
  617. +#!/bin/bash
  618. +
  619. +echo "[ui]" >> $HGRCPATH
  620. +echo "lsdiff=lsdiff" >> $HGRCPATH
  621. +
  622. +mkdir tmp1
  623. +mkdir tmp1/dir
  624. +mkdir tmp2
  625. +mkdir tmp2/dir
  626. +
  627. +echo hi >> tmp1/foo
  628. +echo hi >> tmp1/foo
  629. +echo hi >> tmp1/foo
  630. +echo hi >> tmp1/foo
  631. +
  632. +echo hi >> tmp1/dir/bar
  633. +echo hi >> tmp1/dir/bar
  634. +echo hi >> tmp1/dir/bar
  635. +echo hi >> tmp1/dir/bar
  636. +
  637. +echo hi >> tmp2/foo
  638. +echo h2 >> tmp2/foo
  639. +echo hi >> tmp2/foo
  640. +echo h4 >> tmp2/foo
  641. +
  642. +echo hi >> tmp2/dir/bar
  643. +echo hi >> tmp2/dir/bar
  644. +echo h3 >> tmp2/dir/bar
  645. +echo hi >> tmp2/dir/bar
  646. +
  647. +diff -cNr tmp1 tmp2 > context.patch
  648. +
  649. +cat > patch.py <<EOF
  650. +from mercurial import commands, cmdutil, hg, patch, revlog, util
  651. +from mercurial import ui as _ui
  652. +
  653. +def printaffected(patchfilepath):
  654. +    u = _ui.ui()
  655. +    files = patch.getaffected(patchfilepath, u)
  656. +    for f in files:
  657. +        print f;
  658. +
  659. +print("% testing getaffected: context");
  660. +printaffected("context.patch");
  661. +EOF
  662. +
  663. +python patch.py
  664. diff --git a/tests/test-patch-affected-external.out b/tests/test-patch-affected-external.out
  665. new file mode 100644
  666. --- /dev/null
  667. +++ b/tests/test-patch-affected-external.out
  668.  -0,0 +1,3 @@
  669. +% testing getaffected: context
  670. +dir/bar
  671. +foo
  672. diff --git a/tests/test-patch-affected.out b/tests/test-patch-affected.out
  673. new file mode 100644
  674. --- /dev/null
  675. +++ b/tests/test-patch-affected.out
  676.  -0,0 +1,11 @@
  677. +% testing getaffected: unified
  678. +dir/bar
  679. +foo
  680. +% testing getaffected: ed
  681. +% testing getaffected: normal
  682. +% testing getaffected: context
  683. +dir/bar
  684. +foo
  685. +% testing getaffected: git
  686. +dir/bar
  687. +foo