Merge lp:~abentley/workspace-runner/upload-mime-type into lp:workspace-runner

Proposed by Aaron Bentley on 2015-06-30
Status: Merged
Merged at revision: 22
Proposed branch: lp:~abentley/workspace-runner/upload-mime-type
Merge into: lp:workspace-runner
Diff against target: 116 lines (+66/-4)
2 files modified
workspace_runner/tests/test_upload_artifacts.py (+37/-1)
workspace_runner/upload_artifacts.py (+29/-3)
To merge this branch: bzr merge lp:~abentley/workspace-runner/upload-mime-type
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code 2015-06-30 Approve on 2015-06-30
Review via email: mp+263414@code.launchpad.net

This proposal supersedes a proposal from 2015-06-30.

Commit message

Set content-types for uploads.

Description of the change

In this branch, the upload script can now use file extension to determine Content-Type header.

To post a comment you must log in.
Curtis Hovey (sinzui) wrote :

Thank you. I have a question inline.

review: Needs Information (code)
Curtis Hovey (sinzui) wrote :

We spoke on irc. The mimetypes modules could reduce the number of lines, but we will still need to register some of the special types we have. Can you make sure that I can read *.changes and *.dsc in my browser?

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'workspace_runner/tests/test_upload_artifacts.py'
2--- workspace_runner/tests/test_upload_artifacts.py 2015-06-29 19:19:16 +0000
3+++ workspace_runner/tests/test_upload_artifacts.py 2015-06-30 20:28:44 +0000
4@@ -1,4 +1,5 @@
5 from argparse import Namespace
6+import errno
7 import json
8 import os
9 from tempfile import NamedTemporaryFile
10@@ -12,6 +13,7 @@
11 parse_args,
12 resolve_rules,
13 upload_artifacts,
14+ upload_file,
15 )
16
17
18@@ -75,9 +77,42 @@
19 def __init__(self, path):
20 self.contents = None
21 self.path = path
22+ self.headers = None
23
24- def set_contents_from_file(self, fp):
25+ def set_contents_from_file(self, fp, headers=None):
26 self.contents = fp.read()
27+ self.headers = headers
28+
29+
30+class TestUploadFile(TestCase):
31+
32+ def ct_test(self, mime_type, extension=None, filename=None):
33+ bucket = FakeBucket()
34+ with temp_dir() as files_dir:
35+ if filename is None:
36+ filename = 'foo.{}'.format(extension)
37+ file_path = os.path.join(files_dir, filename)
38+ parent = os.path.dirname(file_path)
39+ try:
40+ os.makedirs(parent)
41+ except OSError as e:
42+ if e.errno != errno.EEXIST:
43+ raise
44+ open(file_path, 'w').close()
45+ upload_file(file_path, 'foo', 'bar', bucket)
46+ self.assertEqual(bucket.keys[0].headers,
47+ {'Content-Type': mime_type})
48+
49+ def test_content_type(self):
50+ self.ct_test('application/gzip', 'tar.gz')
51+ self.ct_test('application/gzip', 'tgz')
52+ self.ct_test('application/json', 'json')
53+ self.ct_test('text/plain', 'txt')
54+ self.ct_test('application/octet-stream', 'foo')
55+ self.ct_test('text/x-yaml; charset=utf-8', 'jenv')
56+ self.ct_test('application/zip', 'zip')
57+ self.ct_test('text/plain', 'log')
58+ self.ct_test('text/plain', filename='foo/consoleText')
59
60
61 class TestUploadArtifacts(TestCase):
62@@ -109,6 +144,7 @@
63 key = bucket.keys[0]
64 self.assertEqual(key.path, 'prefix1/text-files/foo.txt')
65 self.assertEqual(key.contents, 'foo file')
66+ self.assertEqual(key.headers, {'Content-Type': 'text/plain'})
67
68
69 class TestMain(TestCase):
70
71=== modified file 'workspace_runner/upload_artifacts.py'
72--- workspace_runner/upload_artifacts.py 2015-06-30 18:37:21 +0000
73+++ workspace_runner/upload_artifacts.py 2015-06-30 20:28:44 +0000
74@@ -27,13 +27,39 @@
75 return result
76
77
78+def get_media_type(source_name):
79+ """Determine a media type from a filename."""
80+ basename = os.path.basename(source_name)
81+ if basename == 'consoleText':
82+ return 'text/plain'
83+ split_name = basename.rsplit('.', 1)
84+ if len(split_name) == 1:
85+ return 'application/octet-stream'
86+ else:
87+ extension = split_name[-1]
88+ return {
89+ 'gz': 'application/gzip',
90+ 'jenv': 'text/x-yaml; charset=utf-8',
91+ 'json': 'application/json',
92+ 'log': 'text/plain',
93+ 'tgz': 'application/gzip',
94+ 'txt': 'text/plain',
95+ 'zip': 'application/zip',
96+ }.get(extension, 'application/octet-stream')
97+
98+
99+def upload_file(source_name, prefix, dest, bucket):
100+ media_type = get_media_type(source_name)
101+ key = bucket.new_key('/'.join((prefix, dest)))
102+ with open(source_name) as source:
103+ key.set_contents_from_file(source, {'Content-Type': media_type})
104+
105+
106 def upload_artifacts(root, settings, s3_factory=S3Connection):
107 connection = s3_factory(settings['access_key'], settings['secret_key'])
108 bucket = connection.get_bucket(settings['bucket'])
109 for source_name, dest in resolve_rules(root, settings['files']):
110- key = bucket.new_key('/'.join((settings['prefix'], dest)))
111- with open(source_name) as source:
112- key.set_contents_from_file(source)
113+ upload_file(source_name, settings['prefix'], dest, bucket)
114
115
116 def main(argv=None):

Subscribers

People subscribed via source and target branches