Merge lp:~gesha/linaro-license-protection/include-readme into lp:~linaro-automation/linaro-license-protection/trunk

Proposed by Georgy Redkozubov
Status: Merged
Merged at revision: 128
Proposed branch: lp:~gesha/linaro-license-protection/include-readme
Merge into: lp:~linaro-automation/linaro-license-protection/trunk
Diff against target: 422 lines (+287/-0)
14 files modified
license_protected_downloads/tests/test_views.py (+149/-0)
license_protected_downloads/tests/testserver_root/README (+1/-0)
license_protected_downloads/tests/testserver_root/readme/HACKING (+1/-0)
license_protected_downloads/tests/testserver_root/readme/HEADER.html (+37/-0)
license_protected_downloads/tests/testserver_root/readme/INSTALL (+1/-0)
license_protected_downloads/tests/testserver_root/readme/README (+1/-0)
license_protected_downloads/tests/testserver_root/readme/subdir/README (+1/-0)
license_protected_downloads/views.py (+54/-0)
sampleroot/README (+1/-0)
sampleroot/readme/HACKING (+1/-0)
sampleroot/readme/HEADER.html (+37/-0)
sampleroot/readme/INSTALL (+1/-0)
sampleroot/readme/README (+1/-0)
sampleroot/readme/subdir/README (+1/-0)
To merge this branch: bzr merge lp:~gesha/linaro-license-protection/include-readme
Reviewer Review Type Date Requested Status
Данило Шеган (community) Approve
Review via email: mp+125127@code.launchpad.net

Description of the change

This branch adds simple handling for <linaro:include file="README" /> tags to include content from files in HEADER.html.
Only files in the same dir as HEADER.html are processed. If file is found then corresponding tag is replaced with content of file, in all other cases tag is replaced with empty string.

To post a comment you must log in.
Revision history for this message
Данило Шеган (danilo) wrote :
Download full text (4.5 KiB)

Hi Gesha,

Thanks for doing this quickly. I am not a big fan of on-disk test data,
but considering that's the pattern in lp:linaro-license-protection, it's
ok for this branch (we should refactor it some time in the future).

Thanks for writing the tests as well. Comments inline.

  review needs-fixing

У сре, 19. 09 2012. у 08:34 +0000, Georgy Redkozubov пише:

> разлике међу датотекама прилог (review-diff.txt)
> === modified file 'license_protected_downloads/tests/test_views.py'
> --- license_protected_downloads/tests/test_views.py 2012-08-30 09:44:29 +0000
> +++ license_protected_downloads/tests/test_views.py 2012-09-19 08:33:25 +0000
> @@ -486,6 +489,78 @@
> file_path = os.path.join(TESTSERVER_ROOT, target_file)
> self.assertEqual(response['X-Sendfile'], file_path)
>
> + def make_temporary_file(self, data, root=None):
> + """Creates a temporary file and fills it with data.
> +
> + Returns the file name of the new temporary file.
> + """
> + tmp_file_handle, tmp_filename = tempfile.mkstemp(dir=root)
> + tmp_file = os.fdopen(tmp_file_handle, "w")
> + tmp_file.write(data)
> + tmp_file.close()
> + return os.path.basename(tmp_filename)
> +
> + def test_repl(self):

It would be good to split this up into several functions, each one
testing a single corner case/condition (like you do now, but just not in
a single method).

> + target_file = "readme"
> + old_cwd = os.getcwd()
> + file_path = os.path.join(TESTSERVER_ROOT, target_file)
> + os.chdir(file_path)
> + ret = re.sub(r'<linaro:include file="(?P<file_name>.*)"[ ]*/>',
> + repl, 'Test <linaro:include file="README" /> html')

If you just make the regular expression a compiled one and put it
directly in views.py as eg. LINARO_INCLUDE_FILE_RE, you can import that,
and then you'd at least be testing the right RE all the time (i.e. in
this way, we can change the regular expression in the code, code would
stop working, but tests would still pass).

> + self.assertEqual(ret, r"Test Included from README html")

...

> + def test_process_include_tags(self):
> + target_file = "readme"
> + url = urlparse.urljoin("http://testserver/", target_file)
> + response = self.client.get(url, follow=True)
> +
> + self.assertContains(response, r"Included from README")

This one is perfect for an integration test, just enough.

> === modified file 'license_protected_downloads/views.py'
...
> +def repl(m):
> + """
> + Return content of file in current directory otherwise empty string.
> + """

Name and docstring are not very informative. How about

 def process_include_and_read_file()

(That immediately tells you how method actually does two separate
things, and should probably be split into two)

> + content = ''
> + fname = m.group('file_name')
> + dirname = os.path.dirname(fname)
> + if (not dirname or dirname=='.') and os.path.isfile(fname) and not os.path.islink(fname):
> + with open(fname, "r") as infile:
> + content = infile.read()
> +
> + return content

Is it not simpler to check:

  full...

Read more...

review: Needs Fixing
129. By Georgy Redkozubov

Split test into separate functions. Updates based on review comments.

130. By Georgy Redkozubov

Refactored file check

131. By Georgy Redkozubov

Split out parent dir finding. Added tests.

Revision history for this message
Georgy Redkozubov (gesha) wrote :

Danilo,
>
> It would be good to split this up into several functions, each one
> testing a single corner case/condition (like you do now, but just not in
> a single method).
>

done

>
> If you just make the regular expression a compiled one and put it
> directly in views.py as eg. LINARO_INCLUDE_FILE_RE, you can import that,
> and then you'd at least be testing the right RE all the time (i.e. in
> this way, we can change the regular expression in the code, code would
> stop working, but tests would still pass).
>

I thought about it :)

> > +def repl(m):
> > + """
> > + Return content of file in current directory otherwise empty string.
> > + """
>
> Name and docstring are not very informative. How about
>
> def process_include_and_read_file()
>
> (That immediately tells you how method actually does two separate
> things, and should probably be split into two)

This function is only for re.sub() it returns a replacement string and takes only one parameter - match object.
Anyway I've updated name and docstring.

>
> > + content = ''
> > + fname = m.group('file_name')
> > + dirname = os.path.dirname(fname)
> > + if (not dirname or dirname=='.') and os.path.isfile(fname) and not
> os.path.islink(fname):
> > + with open(fname, "r") as infile:
> > + content = infile.read()
> > +
> > + return content
>
> Is it not simpler to check:
>
> full_filename = os.path.join(current_dir, fname)
> normalized_path = os.path.normpath(os.path.realname(full_filename))
> if current_dir == os.path.dirname(normalized_path):
> ....
>
> I'd also split this into a separate method "is_same_parent_dir(parent,
> filename)".
>

Implemented

>
> I generally hate this: we should not depend on cwd in our code, but
> instead pass appropriate parameters (path) around. I know it makes it
> harder for you since you can't simply pass the "repl" as the function to
> run, but it shouldn't be much harder :)
>

I agree, but in our case I don't see any other proper way (may be just now) :)

Revision history for this message
Данило Шеган (danilo) wrote :

Thanks, tests look much neater now. Thanks for the code changes as well, r=me.

As for your comment about getcwd stuff, there was a simple way around it:

  class LinaroIncludeReplacer(object):
      base_path = None

      def read_file_with_include_data(self, matchobj):
          # Assume self.base_path is the allowed path, instead of getcwd().
          ...

  def _process_include_tags(contents, base_path):
      replacer = LinaroIncludeReplacer()
      replacer.base_path = base_path

      contents = LINARO_INCLUDE_FILE_RE.sub(replacer.read_file_with_include_data, contents)
      ...

Anyway, no need to go to these lengths now (there are shorter but less readable tricks involving lambdas as well :), it's looking good, so let's get it landed and email Fathi/Alex when it's up on the server.

PS. You don't have to check for os.path.islink() anymore: the normalization/realpath code resolves all the links.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'license_protected_downloads/tests/test_views.py'
--- license_protected_downloads/tests/test_views.py 2012-08-30 09:44:29 +0000
+++ license_protected_downloads/tests/test_views.py 2012-09-19 14:45:33 +0000
@@ -6,11 +6,14 @@
6import os6import os
7import unittest7import unittest
8import urlparse8import urlparse
9import tempfile
910
10from license_protected_downloads import bzr_version11from license_protected_downloads import bzr_version
11from license_protected_downloads.buildinfo import BuildInfo12from license_protected_downloads.buildinfo import BuildInfo
12from license_protected_downloads.views import _insert_license_into_db13from license_protected_downloads.views import _insert_license_into_db
13from license_protected_downloads.views import _sizeof_fmt14from license_protected_downloads.views import _sizeof_fmt
15from license_protected_downloads.views import _process_include_tags
16from license_protected_downloads.views import is_same_parent_dir
14from license_protected_downloads.config import INTERNAL_HOSTS17from license_protected_downloads.config import INTERNAL_HOSTS
1518
1619
@@ -486,6 +489,152 @@
486 file_path = os.path.join(TESTSERVER_ROOT, target_file)489 file_path = os.path.join(TESTSERVER_ROOT, target_file)
487 self.assertEqual(response['X-Sendfile'], file_path)490 self.assertEqual(response['X-Sendfile'], file_path)
488491
492 def make_temporary_file(self, data, root=None):
493 """Creates a temporary file and fills it with data.
494
495 Returns the file name of the new temporary file.
496 """
497 tmp_file_handle, tmp_filename = tempfile.mkstemp(dir=root)
498 tmp_file = os.fdopen(tmp_file_handle, "w")
499 tmp_file.write(data)
500 tmp_file.close()
501 return os.path.basename(tmp_filename)
502
503 def test_replace_self_closing_tag(self):
504 target_file = "readme"
505 old_cwd = os.getcwd()
506 file_path = os.path.join(TESTSERVER_ROOT, target_file)
507 os.chdir(file_path)
508 ret = _process_include_tags(
509 'Test <linaro:include file="README" /> html')
510 self.assertEqual(ret, r"Test Included from README html")
511 os.chdir(old_cwd)
512
513 def test_replace_self_closing_tag1(self):
514 target_file = "readme"
515 old_cwd = os.getcwd()
516 file_path = os.path.join(TESTSERVER_ROOT, target_file)
517 os.chdir(file_path)
518 ret = _process_include_tags(
519 'Test <linaro:include file="README"/> html')
520 self.assertEqual(ret, r"Test Included from README html")
521 os.chdir(old_cwd)
522
523 def test_replace_with_closing_tag(self):
524 target_file = "readme"
525 old_cwd = os.getcwd()
526 file_path = os.path.join(TESTSERVER_ROOT, target_file)
527 os.chdir(file_path)
528 ret = _process_include_tags(
529 'Test <linaro:include file="README">README is missing</linaro:include> html')
530 self.assertEqual(ret, r"Test Included from README html")
531 os.chdir(old_cwd)
532
533 def test_replace_non_existent_file(self):
534 target_file = "readme"
535 old_cwd = os.getcwd()
536 file_path = os.path.join(TESTSERVER_ROOT, target_file)
537 os.chdir(file_path)
538 ret = _process_include_tags(
539 'Test <linaro:include file="NON_EXISTENT_FILE" /> html')
540 self.assertEqual(ret, r"Test html")
541 os.chdir(old_cwd)
542
543 def test_replace_empty_file_property(self):
544 target_file = "readme"
545 old_cwd = os.getcwd()
546 file_path = os.path.join(TESTSERVER_ROOT, target_file)
547 os.chdir(file_path)
548 ret = _process_include_tags(
549 'Test <linaro:include file="" /> html')
550 self.assertEqual(ret, r"Test html")
551 os.chdir(old_cwd)
552
553 def test_replace_parent_dir(self):
554 target_file = "readme"
555 old_cwd = os.getcwd()
556 file_path = os.path.join(TESTSERVER_ROOT, target_file)
557 os.chdir(file_path)
558 ret = _process_include_tags(
559 'Test <linaro:include file="../README" /> html')
560 self.assertEqual(ret, r"Test html")
561 os.chdir(old_cwd)
562
563 def test_replace_subdir(self):
564 target_file = "readme"
565 old_cwd = os.getcwd()
566 file_path = os.path.join(TESTSERVER_ROOT, target_file)
567 os.chdir(file_path)
568 ret = _process_include_tags(
569 'Test <linaro:include file="subdir/README" /> html')
570 self.assertEqual(ret, r"Test html")
571 os.chdir(old_cwd)
572
573 def test_replace_subdir_parent_dir(self):
574 target_file = "readme"
575 old_cwd = os.getcwd()
576 file_path = os.path.join(TESTSERVER_ROOT, target_file)
577 os.chdir(file_path)
578 ret = _process_include_tags(
579 'Test <linaro:include file="subdir/../README" /> html')
580 self.assertEqual(ret, r"Test Included from README html")
581 os.chdir(old_cwd)
582
583 def test_replace_full_path(self):
584 target_file = "readme"
585 old_cwd = os.getcwd()
586 file_path = os.path.join(TESTSERVER_ROOT, target_file)
587 os.chdir(file_path)
588 tmp = self.make_temporary_file("Included from /tmp", root="/tmp")
589 ret = _process_include_tags(
590 'Test <linaro:include file="/tmp/%s" /> html' % tmp)
591 self.assertEqual(ret, r"Test html")
592 os.chdir(old_cwd)
593
594 def test_replace_self_dir(self):
595 target_file = "readme"
596 old_cwd = os.getcwd()
597 file_path = os.path.join(TESTSERVER_ROOT, target_file)
598 os.chdir(file_path)
599 ret = _process_include_tags(
600 'Test <linaro:include file="./README" /> html')
601 self.assertEqual(ret, r"Test Included from README html")
602 os.chdir(old_cwd)
603
604 def test_replace_self_parent_dir(self):
605 target_file = "readme"
606 old_cwd = os.getcwd()
607 file_path = os.path.join(TESTSERVER_ROOT, target_file)
608 os.chdir(file_path)
609 ret = _process_include_tags(
610 'Test <linaro:include file="./../README" /> html')
611 self.assertEqual(ret, r"Test html")
612 os.chdir(old_cwd)
613
614 def test_replace_symlink(self):
615 target_file = "readme"
616 old_cwd = os.getcwd()
617 file_path = os.path.join(TESTSERVER_ROOT, target_file)
618 os.chdir(file_path)
619 ret = _process_include_tags(
620 'Test <linaro:include file="READMELINK" /> html')
621 self.assertEqual(ret, r"Test html")
622 os.chdir(old_cwd)
623
624 def test_process_include_tags(self):
625 target_file = "readme"
626 url = urlparse.urljoin("http://testserver/", target_file)
627 response = self.client.get(url, follow=True)
628
629 self.assertContains(response, r"Included from README")
630
631 def test_is_same_parent_dir_true(self):
632 fname = os.path.join(TESTSERVER_ROOT, "subdir/../file")
633 self.assertTrue(is_same_parent_dir(TESTSERVER_ROOT, fname))
634
635 def test_is_same_parent_dir_false(self):
636 fname = os.path.join(TESTSERVER_ROOT, "../file")
637 self.assertFalse(is_same_parent_dir(TESTSERVER_ROOT, fname))
489638
490if __name__ == '__main__':639if __name__ == '__main__':
491 unittest.main()640 unittest.main()
492641
=== added file 'license_protected_downloads/tests/testserver_root/README'
--- license_protected_downloads/tests/testserver_root/README 1970-01-01 00:00:00 +0000
+++ license_protected_downloads/tests/testserver_root/README 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from ../README
0\ No newline at end of file2\ No newline at end of file
13
=== added directory 'license_protected_downloads/tests/testserver_root/readme'
=== added file 'license_protected_downloads/tests/testserver_root/readme/HACKING'
--- license_protected_downloads/tests/testserver_root/readme/HACKING 1970-01-01 00:00:00 +0000
+++ license_protected_downloads/tests/testserver_root/readme/HACKING 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from HACKING
0\ No newline at end of file2\ No newline at end of file
13
=== added file 'license_protected_downloads/tests/testserver_root/readme/HEADER.html'
--- license_protected_downloads/tests/testserver_root/readme/HEADER.html 1970-01-01 00:00:00 +0000
+++ license_protected_downloads/tests/testserver_root/readme/HEADER.html 2012-09-19 14:45:33 +0000
@@ -0,0 +1,37 @@
1<html>
2<head>
3</head>
4<body>
5 <div id="content"><meta http-equiv="content-type" content="text/html; charset=utf-8" />
6 <h2>Sample includes</h2>
7 <br />
8 <h2><pre>&lt;linaro:include file="README" /&gt;</pre></h2>
9 <pre style="font-size:.85em; padding:0 0 0 10;">
10 <linaro:include file="README" />
11 </pre>
12 <h2><pre>&lt;linaro:include file="INSTALL"/&gt;</pre></h2>
13 <pre style="font-size:.85em; padding:0 0 0 10;">
14 <linaro:include file="INSTALL"/>
15 </pre>
16 <h2><pre>&lt;linaro:include file="HACKING"&gt;HACKING is missing&lt;/linaro:include&gt;</pre></h2>
17 <pre style="font-size:.85em; padding:0 0 0 10;">
18 <linaro:include file="HACKING">HACKING is missing</linaro:include>
19 </pre>
20 <h2><pre>&lt;linaro:include file="subdir/README"/&gt;</pre></h2>
21 <pre style="font-size:.85em; padding:0 0 0 10;">
22 <linaro:include file="subdir/README"/>
23 </pre>
24 <h2><pre>&lt;linaro:include file="subdir/../README"/&gt;</pre></h2>
25 <pre style="font-size:.85em; padding:0 0 0 10;">
26 <linaro:include file="../README"/>
27 </pre>
28 <h2><pre>&lt;linaro:include file="/tmp/README"/&gt;</pre></h2>
29 <pre style="font-size:.85em; padding:0 0 0 10;">
30 <linaro:include file="/tmp/README"/>
31 </pre>
32 <h2><pre>&lt;linaro:include file="READMELINK"/&gt;</pre></h2>
33 <pre style="font-size:.85em; padding:0 0 0 10;">
34 <linaro:include file="READMELINK"/>
35 </pre>
36</body>
37</html>
0\ No newline at end of file38\ No newline at end of file
139
=== added file 'license_protected_downloads/tests/testserver_root/readme/INSTALL'
--- license_protected_downloads/tests/testserver_root/readme/INSTALL 1970-01-01 00:00:00 +0000
+++ license_protected_downloads/tests/testserver_root/readme/INSTALL 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from INSTALL
0\ No newline at end of file2\ No newline at end of file
13
=== added file 'license_protected_downloads/tests/testserver_root/readme/README'
--- license_protected_downloads/tests/testserver_root/readme/README 1970-01-01 00:00:00 +0000
+++ license_protected_downloads/tests/testserver_root/readme/README 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from README
0\ No newline at end of file2\ No newline at end of file
13
=== added symlink 'license_protected_downloads/tests/testserver_root/readme/READMELINK'
=== target is u'../README'
=== added directory 'license_protected_downloads/tests/testserver_root/readme/subdir'
=== added file 'license_protected_downloads/tests/testserver_root/readme/subdir/README'
--- license_protected_downloads/tests/testserver_root/readme/subdir/README 1970-01-01 00:00:00 +0000
+++ license_protected_downloads/tests/testserver_root/readme/subdir/README 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from subdir/README
0\ No newline at end of file2\ No newline at end of file
13
=== modified file 'license_protected_downloads/views.py'
--- license_protected_downloads/views.py 2012-08-30 09:44:29 +0000
+++ license_protected_downloads/views.py 2012-09-19 14:45:33 +0000
@@ -25,6 +25,10 @@
25import config25import config
2626
2727
28LINARO_INCLUDE_FILE_RE = re.compile(r'<linaro:include file="(?P<file_name>.*)"[ ]*/>')
29LINARO_INCLUDE_FILE_RE1 = re.compile(r'<linaro:include file="(?P<file_name>.*)">(.*)</linaro:include>')
30
31
28def _hidden_file(file_name):32def _hidden_file(file_name):
29 hidden_files = ["BUILD-INFO.txt", "EULA.txt", r"^\.", "HEADER.html"]33 hidden_files = ["BUILD-INFO.txt", "EULA.txt", r"^\.", "HEADER.html"]
30 for pattern in hidden_files:34 for pattern in hidden_files:
@@ -149,13 +153,60 @@
149 if os.path.isfile(header_html):153 if os.path.isfile(header_html):
150 with open(header_html, "r") as infile:154 with open(header_html, "r") as infile:
151 body = infile.read()155 body = infile.read()
156 body = _process_include_tags(body)
152 soup = BeautifulSoup(body)157 soup = BeautifulSoup(body)
153 for chunk in soup.findAll(id="content"):158 for chunk in soup.findAll(id="content"):
154 header_content += chunk.prettify().decode("utf-8")159 header_content += chunk.prettify().decode("utf-8")
155 header_content = '\n'.join(header_content.split('\n')[1:-1])160 header_content = '\n'.join(header_content.split('\n')[1:-1])
161
156 return header_content162 return header_content
157163
158164
165def is_same_parent_dir(parent, filename):
166 """
167 Checks if filename's parent dir is parent.
168 """
169 full_filename = os.path.join(parent, filename)
170 normalized_path = os.path.normpath(os.path.realpath(full_filename))
171 if parent == os.path.dirname(normalized_path):
172 return True
173
174 return False
175
176
177def read_file_with_include_data(matchobj):
178 """
179 Function to get data for re.sub() in _process_include_tags() from file
180 which name is in named match group 'file_name'.
181 Returns content of file in current directory otherwise empty string.
182 """
183 content = ''
184 current_dir = os.getcwd()
185 fname = matchobj.group('file_name')
186 if is_same_parent_dir(current_dir, fname):
187 if os.path.isfile(fname) and not os.path.islink(fname):
188 with open(fname, "r") as infile:
189 content = infile.read()
190
191 return content
192
193
194def _process_include_tags(content):
195 """
196 Replaces <linaro:include file="README" /> or
197 <linaro:include file="README">text to show</linaro:include> tags
198 with content of README file or empty string if file not found or
199 not allowed.
200 """
201 content = re.sub(LINARO_INCLUDE_FILE_RE,
202 read_file_with_include_data,
203 content)
204 content = re.sub(LINARO_INCLUDE_FILE_RE1,
205 read_file_with_include_data,
206 content)
207 return content
208
209
159def is_protected(path):210def is_protected(path):
160 build_info = None211 build_info = None
161 max_index = 1212 max_index = 1
@@ -336,7 +387,10 @@
336 else:387 else:
337 up_dir = None388 up_dir = None
338389
390 old_cwd = os.getcwd()
391 os.chdir(path)
339 header_content = _get_header_html_content(path)392 header_content = _get_header_html_content(path)
393 os.chdir(old_cwd)
340 download = None394 download = None
341 if 'dl' in request.GET:395 if 'dl' in request.GET:
342 download = request.GET['dl']396 download = request.GET['dl']
343397
=== added file 'sampleroot/README'
--- sampleroot/README 1970-01-01 00:00:00 +0000
+++ sampleroot/README 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from ../README
0\ No newline at end of file2\ No newline at end of file
13
=== added directory 'sampleroot/readme'
=== added file 'sampleroot/readme/HACKING'
--- sampleroot/readme/HACKING 1970-01-01 00:00:00 +0000
+++ sampleroot/readme/HACKING 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from HACKING
0\ No newline at end of file2\ No newline at end of file
13
=== added file 'sampleroot/readme/HEADER.html'
--- sampleroot/readme/HEADER.html 1970-01-01 00:00:00 +0000
+++ sampleroot/readme/HEADER.html 2012-09-19 14:45:33 +0000
@@ -0,0 +1,37 @@
1<html>
2<head>
3</head>
4<body>
5 <div id="content"><meta http-equiv="content-type" content="text/html; charset=utf-8" />
6 <h2>Sample includes</h2>
7 <br />
8 <h2><pre>&lt;linaro:include file="README" /&gt;</pre></h2>
9 <pre style="font-size:.85em; padding:0 0 0 10;">
10 <linaro:include file="README" />
11 </pre>
12 <h2><pre>&lt;linaro:include file="INSTALL"/&gt;</pre></h2>
13 <pre style="font-size:.85em; padding:0 0 0 10;">
14 <linaro:include file="INSTALL"/>
15 </pre>
16 <h2><pre>&lt;linaro:include file="HACKING"&gt;HACKING is missing&lt;/linaro:include&gt;</pre></h2>
17 <pre style="font-size:.85em; padding:0 0 0 10;">
18 <linaro:include file="HACKING">HACKING is missing</linaro:include>
19 </pre>
20 <h2><pre>&lt;linaro:include file="subdir/README"/&gt;</pre></h2>
21 <pre style="font-size:.85em; padding:0 0 0 10;">
22 <linaro:include file="subdir/README"/>
23 </pre>
24 <h2><pre>&lt;linaro:include file="subdir/../README"/&gt;</pre></h2>
25 <pre style="font-size:.85em; padding:0 0 0 10;">
26 <linaro:include file="../README"/>
27 </pre>
28 <h2><pre>&lt;linaro:include file="/tmp/README"/&gt;</pre></h2>
29 <pre style="font-size:.85em; padding:0 0 0 10;">
30 <linaro:include file="/tmp/README"/>
31 </pre>
32 <h2><pre>&lt;linaro:include file="READMELINK"/&gt;</pre></h2>
33 <pre style="font-size:.85em; padding:0 0 0 10;">
34 <linaro:include file="READMELINK"/>
35 </pre>
36</body>
37</html>
0\ No newline at end of file38\ No newline at end of file
139
=== added file 'sampleroot/readme/INSTALL'
--- sampleroot/readme/INSTALL 1970-01-01 00:00:00 +0000
+++ sampleroot/readme/INSTALL 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from INSTALL
0\ No newline at end of file2\ No newline at end of file
13
=== added file 'sampleroot/readme/README'
--- sampleroot/readme/README 1970-01-01 00:00:00 +0000
+++ sampleroot/readme/README 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from README
0\ No newline at end of file2\ No newline at end of file
13
=== added symlink 'sampleroot/readme/READMELINK'
=== target is u'../README'
=== added directory 'sampleroot/readme/subdir'
=== added file 'sampleroot/readme/subdir/README'
--- sampleroot/readme/subdir/README 1970-01-01 00:00:00 +0000
+++ sampleroot/readme/subdir/README 2012-09-19 14:45:33 +0000
@@ -0,0 +1,1 @@
1Included from subdir/README
0\ No newline at end of file2\ No newline at end of file

Subscribers

People subscribed via source and target branches