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
1=== modified file 'license_protected_downloads/tests/test_views.py'
2--- license_protected_downloads/tests/test_views.py 2012-08-30 09:44:29 +0000
3+++ license_protected_downloads/tests/test_views.py 2012-09-19 14:45:33 +0000
4@@ -6,11 +6,14 @@
5 import os
6 import unittest
7 import urlparse
8+import tempfile
9
10 from license_protected_downloads import bzr_version
11 from license_protected_downloads.buildinfo import BuildInfo
12 from license_protected_downloads.views import _insert_license_into_db
13 from license_protected_downloads.views import _sizeof_fmt
14+from license_protected_downloads.views import _process_include_tags
15+from license_protected_downloads.views import is_same_parent_dir
16 from license_protected_downloads.config import INTERNAL_HOSTS
17
18
19@@ -486,6 +489,152 @@
20 file_path = os.path.join(TESTSERVER_ROOT, target_file)
21 self.assertEqual(response['X-Sendfile'], file_path)
22
23+ def make_temporary_file(self, data, root=None):
24+ """Creates a temporary file and fills it with data.
25+
26+ Returns the file name of the new temporary file.
27+ """
28+ tmp_file_handle, tmp_filename = tempfile.mkstemp(dir=root)
29+ tmp_file = os.fdopen(tmp_file_handle, "w")
30+ tmp_file.write(data)
31+ tmp_file.close()
32+ return os.path.basename(tmp_filename)
33+
34+ def test_replace_self_closing_tag(self):
35+ target_file = "readme"
36+ old_cwd = os.getcwd()
37+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
38+ os.chdir(file_path)
39+ ret = _process_include_tags(
40+ 'Test <linaro:include file="README" /> html')
41+ self.assertEqual(ret, r"Test Included from README html")
42+ os.chdir(old_cwd)
43+
44+ def test_replace_self_closing_tag1(self):
45+ target_file = "readme"
46+ old_cwd = os.getcwd()
47+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
48+ os.chdir(file_path)
49+ ret = _process_include_tags(
50+ 'Test <linaro:include file="README"/> html')
51+ self.assertEqual(ret, r"Test Included from README html")
52+ os.chdir(old_cwd)
53+
54+ def test_replace_with_closing_tag(self):
55+ target_file = "readme"
56+ old_cwd = os.getcwd()
57+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
58+ os.chdir(file_path)
59+ ret = _process_include_tags(
60+ 'Test <linaro:include file="README">README is missing</linaro:include> html')
61+ self.assertEqual(ret, r"Test Included from README html")
62+ os.chdir(old_cwd)
63+
64+ def test_replace_non_existent_file(self):
65+ target_file = "readme"
66+ old_cwd = os.getcwd()
67+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
68+ os.chdir(file_path)
69+ ret = _process_include_tags(
70+ 'Test <linaro:include file="NON_EXISTENT_FILE" /> html')
71+ self.assertEqual(ret, r"Test html")
72+ os.chdir(old_cwd)
73+
74+ def test_replace_empty_file_property(self):
75+ target_file = "readme"
76+ old_cwd = os.getcwd()
77+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
78+ os.chdir(file_path)
79+ ret = _process_include_tags(
80+ 'Test <linaro:include file="" /> html')
81+ self.assertEqual(ret, r"Test html")
82+ os.chdir(old_cwd)
83+
84+ def test_replace_parent_dir(self):
85+ target_file = "readme"
86+ old_cwd = os.getcwd()
87+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
88+ os.chdir(file_path)
89+ ret = _process_include_tags(
90+ 'Test <linaro:include file="../README" /> html')
91+ self.assertEqual(ret, r"Test html")
92+ os.chdir(old_cwd)
93+
94+ def test_replace_subdir(self):
95+ target_file = "readme"
96+ old_cwd = os.getcwd()
97+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
98+ os.chdir(file_path)
99+ ret = _process_include_tags(
100+ 'Test <linaro:include file="subdir/README" /> html')
101+ self.assertEqual(ret, r"Test html")
102+ os.chdir(old_cwd)
103+
104+ def test_replace_subdir_parent_dir(self):
105+ target_file = "readme"
106+ old_cwd = os.getcwd()
107+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
108+ os.chdir(file_path)
109+ ret = _process_include_tags(
110+ 'Test <linaro:include file="subdir/../README" /> html')
111+ self.assertEqual(ret, r"Test Included from README html")
112+ os.chdir(old_cwd)
113+
114+ def test_replace_full_path(self):
115+ target_file = "readme"
116+ old_cwd = os.getcwd()
117+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
118+ os.chdir(file_path)
119+ tmp = self.make_temporary_file("Included from /tmp", root="/tmp")
120+ ret = _process_include_tags(
121+ 'Test <linaro:include file="/tmp/%s" /> html' % tmp)
122+ self.assertEqual(ret, r"Test html")
123+ os.chdir(old_cwd)
124+
125+ def test_replace_self_dir(self):
126+ target_file = "readme"
127+ old_cwd = os.getcwd()
128+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
129+ os.chdir(file_path)
130+ ret = _process_include_tags(
131+ 'Test <linaro:include file="./README" /> html')
132+ self.assertEqual(ret, r"Test Included from README html")
133+ os.chdir(old_cwd)
134+
135+ def test_replace_self_parent_dir(self):
136+ target_file = "readme"
137+ old_cwd = os.getcwd()
138+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
139+ os.chdir(file_path)
140+ ret = _process_include_tags(
141+ 'Test <linaro:include file="./../README" /> html')
142+ self.assertEqual(ret, r"Test html")
143+ os.chdir(old_cwd)
144+
145+ def test_replace_symlink(self):
146+ target_file = "readme"
147+ old_cwd = os.getcwd()
148+ file_path = os.path.join(TESTSERVER_ROOT, target_file)
149+ os.chdir(file_path)
150+ ret = _process_include_tags(
151+ 'Test <linaro:include file="READMELINK" /> html')
152+ self.assertEqual(ret, r"Test html")
153+ os.chdir(old_cwd)
154+
155+ def test_process_include_tags(self):
156+ target_file = "readme"
157+ url = urlparse.urljoin("http://testserver/", target_file)
158+ response = self.client.get(url, follow=True)
159+
160+ self.assertContains(response, r"Included from README")
161+
162+ def test_is_same_parent_dir_true(self):
163+ fname = os.path.join(TESTSERVER_ROOT, "subdir/../file")
164+ self.assertTrue(is_same_parent_dir(TESTSERVER_ROOT, fname))
165+
166+ def test_is_same_parent_dir_false(self):
167+ fname = os.path.join(TESTSERVER_ROOT, "../file")
168+ self.assertFalse(is_same_parent_dir(TESTSERVER_ROOT, fname))
169
170 if __name__ == '__main__':
171 unittest.main()
172
173=== added file 'license_protected_downloads/tests/testserver_root/README'
174--- license_protected_downloads/tests/testserver_root/README 1970-01-01 00:00:00 +0000
175+++ license_protected_downloads/tests/testserver_root/README 2012-09-19 14:45:33 +0000
176@@ -0,0 +1,1 @@
177+Included from ../README
178\ No newline at end of file
179
180=== added directory 'license_protected_downloads/tests/testserver_root/readme'
181=== added file 'license_protected_downloads/tests/testserver_root/readme/HACKING'
182--- license_protected_downloads/tests/testserver_root/readme/HACKING 1970-01-01 00:00:00 +0000
183+++ license_protected_downloads/tests/testserver_root/readme/HACKING 2012-09-19 14:45:33 +0000
184@@ -0,0 +1,1 @@
185+Included from HACKING
186\ No newline at end of file
187
188=== added file 'license_protected_downloads/tests/testserver_root/readme/HEADER.html'
189--- license_protected_downloads/tests/testserver_root/readme/HEADER.html 1970-01-01 00:00:00 +0000
190+++ license_protected_downloads/tests/testserver_root/readme/HEADER.html 2012-09-19 14:45:33 +0000
191@@ -0,0 +1,37 @@
192+<html>
193+<head>
194+</head>
195+<body>
196+ <div id="content"><meta http-equiv="content-type" content="text/html; charset=utf-8" />
197+ <h2>Sample includes</h2>
198+ <br />
199+ <h2><pre>&lt;linaro:include file="README" /&gt;</pre></h2>
200+ <pre style="font-size:.85em; padding:0 0 0 10;">
201+ <linaro:include file="README" />
202+ </pre>
203+ <h2><pre>&lt;linaro:include file="INSTALL"/&gt;</pre></h2>
204+ <pre style="font-size:.85em; padding:0 0 0 10;">
205+ <linaro:include file="INSTALL"/>
206+ </pre>
207+ <h2><pre>&lt;linaro:include file="HACKING"&gt;HACKING is missing&lt;/linaro:include&gt;</pre></h2>
208+ <pre style="font-size:.85em; padding:0 0 0 10;">
209+ <linaro:include file="HACKING">HACKING is missing</linaro:include>
210+ </pre>
211+ <h2><pre>&lt;linaro:include file="subdir/README"/&gt;</pre></h2>
212+ <pre style="font-size:.85em; padding:0 0 0 10;">
213+ <linaro:include file="subdir/README"/>
214+ </pre>
215+ <h2><pre>&lt;linaro:include file="subdir/../README"/&gt;</pre></h2>
216+ <pre style="font-size:.85em; padding:0 0 0 10;">
217+ <linaro:include file="../README"/>
218+ </pre>
219+ <h2><pre>&lt;linaro:include file="/tmp/README"/&gt;</pre></h2>
220+ <pre style="font-size:.85em; padding:0 0 0 10;">
221+ <linaro:include file="/tmp/README"/>
222+ </pre>
223+ <h2><pre>&lt;linaro:include file="READMELINK"/&gt;</pre></h2>
224+ <pre style="font-size:.85em; padding:0 0 0 10;">
225+ <linaro:include file="READMELINK"/>
226+ </pre>
227+</body>
228+</html>
229\ No newline at end of file
230
231=== added file 'license_protected_downloads/tests/testserver_root/readme/INSTALL'
232--- license_protected_downloads/tests/testserver_root/readme/INSTALL 1970-01-01 00:00:00 +0000
233+++ license_protected_downloads/tests/testserver_root/readme/INSTALL 2012-09-19 14:45:33 +0000
234@@ -0,0 +1,1 @@
235+Included from INSTALL
236\ No newline at end of file
237
238=== added file 'license_protected_downloads/tests/testserver_root/readme/README'
239--- license_protected_downloads/tests/testserver_root/readme/README 1970-01-01 00:00:00 +0000
240+++ license_protected_downloads/tests/testserver_root/readme/README 2012-09-19 14:45:33 +0000
241@@ -0,0 +1,1 @@
242+Included from README
243\ No newline at end of file
244
245=== added symlink 'license_protected_downloads/tests/testserver_root/readme/READMELINK'
246=== target is u'../README'
247=== added directory 'license_protected_downloads/tests/testserver_root/readme/subdir'
248=== added file 'license_protected_downloads/tests/testserver_root/readme/subdir/README'
249--- license_protected_downloads/tests/testserver_root/readme/subdir/README 1970-01-01 00:00:00 +0000
250+++ license_protected_downloads/tests/testserver_root/readme/subdir/README 2012-09-19 14:45:33 +0000
251@@ -0,0 +1,1 @@
252+Included from subdir/README
253\ No newline at end of file
254
255=== modified file 'license_protected_downloads/views.py'
256--- license_protected_downloads/views.py 2012-08-30 09:44:29 +0000
257+++ license_protected_downloads/views.py 2012-09-19 14:45:33 +0000
258@@ -25,6 +25,10 @@
259 import config
260
261
262+LINARO_INCLUDE_FILE_RE = re.compile(r'<linaro:include file="(?P<file_name>.*)"[ ]*/>')
263+LINARO_INCLUDE_FILE_RE1 = re.compile(r'<linaro:include file="(?P<file_name>.*)">(.*)</linaro:include>')
264+
265+
266 def _hidden_file(file_name):
267 hidden_files = ["BUILD-INFO.txt", "EULA.txt", r"^\.", "HEADER.html"]
268 for pattern in hidden_files:
269@@ -149,13 +153,60 @@
270 if os.path.isfile(header_html):
271 with open(header_html, "r") as infile:
272 body = infile.read()
273+ body = _process_include_tags(body)
274 soup = BeautifulSoup(body)
275 for chunk in soup.findAll(id="content"):
276 header_content += chunk.prettify().decode("utf-8")
277 header_content = '\n'.join(header_content.split('\n')[1:-1])
278+
279 return header_content
280
281
282+def is_same_parent_dir(parent, filename):
283+ """
284+ Checks if filename's parent dir is parent.
285+ """
286+ full_filename = os.path.join(parent, filename)
287+ normalized_path = os.path.normpath(os.path.realpath(full_filename))
288+ if parent == os.path.dirname(normalized_path):
289+ return True
290+
291+ return False
292+
293+
294+def read_file_with_include_data(matchobj):
295+ """
296+ Function to get data for re.sub() in _process_include_tags() from file
297+ which name is in named match group 'file_name'.
298+ Returns content of file in current directory otherwise empty string.
299+ """
300+ content = ''
301+ current_dir = os.getcwd()
302+ fname = matchobj.group('file_name')
303+ if is_same_parent_dir(current_dir, fname):
304+ if os.path.isfile(fname) and not os.path.islink(fname):
305+ with open(fname, "r") as infile:
306+ content = infile.read()
307+
308+ return content
309+
310+
311+def _process_include_tags(content):
312+ """
313+ Replaces <linaro:include file="README" /> or
314+ <linaro:include file="README">text to show</linaro:include> tags
315+ with content of README file or empty string if file not found or
316+ not allowed.
317+ """
318+ content = re.sub(LINARO_INCLUDE_FILE_RE,
319+ read_file_with_include_data,
320+ content)
321+ content = re.sub(LINARO_INCLUDE_FILE_RE1,
322+ read_file_with_include_data,
323+ content)
324+ return content
325+
326+
327 def is_protected(path):
328 build_info = None
329 max_index = 1
330@@ -336,7 +387,10 @@
331 else:
332 up_dir = None
333
334+ old_cwd = os.getcwd()
335+ os.chdir(path)
336 header_content = _get_header_html_content(path)
337+ os.chdir(old_cwd)
338 download = None
339 if 'dl' in request.GET:
340 download = request.GET['dl']
341
342=== added file 'sampleroot/README'
343--- sampleroot/README 1970-01-01 00:00:00 +0000
344+++ sampleroot/README 2012-09-19 14:45:33 +0000
345@@ -0,0 +1,1 @@
346+Included from ../README
347\ No newline at end of file
348
349=== added directory 'sampleroot/readme'
350=== added file 'sampleroot/readme/HACKING'
351--- sampleroot/readme/HACKING 1970-01-01 00:00:00 +0000
352+++ sampleroot/readme/HACKING 2012-09-19 14:45:33 +0000
353@@ -0,0 +1,1 @@
354+Included from HACKING
355\ No newline at end of file
356
357=== added file 'sampleroot/readme/HEADER.html'
358--- sampleroot/readme/HEADER.html 1970-01-01 00:00:00 +0000
359+++ sampleroot/readme/HEADER.html 2012-09-19 14:45:33 +0000
360@@ -0,0 +1,37 @@
361+<html>
362+<head>
363+</head>
364+<body>
365+ <div id="content"><meta http-equiv="content-type" content="text/html; charset=utf-8" />
366+ <h2>Sample includes</h2>
367+ <br />
368+ <h2><pre>&lt;linaro:include file="README" /&gt;</pre></h2>
369+ <pre style="font-size:.85em; padding:0 0 0 10;">
370+ <linaro:include file="README" />
371+ </pre>
372+ <h2><pre>&lt;linaro:include file="INSTALL"/&gt;</pre></h2>
373+ <pre style="font-size:.85em; padding:0 0 0 10;">
374+ <linaro:include file="INSTALL"/>
375+ </pre>
376+ <h2><pre>&lt;linaro:include file="HACKING"&gt;HACKING is missing&lt;/linaro:include&gt;</pre></h2>
377+ <pre style="font-size:.85em; padding:0 0 0 10;">
378+ <linaro:include file="HACKING">HACKING is missing</linaro:include>
379+ </pre>
380+ <h2><pre>&lt;linaro:include file="subdir/README"/&gt;</pre></h2>
381+ <pre style="font-size:.85em; padding:0 0 0 10;">
382+ <linaro:include file="subdir/README"/>
383+ </pre>
384+ <h2><pre>&lt;linaro:include file="subdir/../README"/&gt;</pre></h2>
385+ <pre style="font-size:.85em; padding:0 0 0 10;">
386+ <linaro:include file="../README"/>
387+ </pre>
388+ <h2><pre>&lt;linaro:include file="/tmp/README"/&gt;</pre></h2>
389+ <pre style="font-size:.85em; padding:0 0 0 10;">
390+ <linaro:include file="/tmp/README"/>
391+ </pre>
392+ <h2><pre>&lt;linaro:include file="READMELINK"/&gt;</pre></h2>
393+ <pre style="font-size:.85em; padding:0 0 0 10;">
394+ <linaro:include file="READMELINK"/>
395+ </pre>
396+</body>
397+</html>
398\ No newline at end of file
399
400=== added file 'sampleroot/readme/INSTALL'
401--- sampleroot/readme/INSTALL 1970-01-01 00:00:00 +0000
402+++ sampleroot/readme/INSTALL 2012-09-19 14:45:33 +0000
403@@ -0,0 +1,1 @@
404+Included from INSTALL
405\ No newline at end of file
406
407=== added file 'sampleroot/readme/README'
408--- sampleroot/readme/README 1970-01-01 00:00:00 +0000
409+++ sampleroot/readme/README 2012-09-19 14:45:33 +0000
410@@ -0,0 +1,1 @@
411+Included from README
412\ No newline at end of file
413
414=== added symlink 'sampleroot/readme/READMELINK'
415=== target is u'../README'
416=== added directory 'sampleroot/readme/subdir'
417=== added file 'sampleroot/readme/subdir/README'
418--- sampleroot/readme/subdir/README 1970-01-01 00:00:00 +0000
419+++ sampleroot/readme/subdir/README 2012-09-19 14:45:33 +0000
420@@ -0,0 +1,1 @@
421+Included from subdir/README
422\ No newline at end of file

Subscribers

People subscribed via source and target branches