OLD | NEW |
1 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 # for details. All rights reserved. Use of this source code is governed by a | 2 # for details. All rights reserved. Use of this source code is governed by a |
3 # BSD-style license that can be found in the LICENSE file. | 3 # BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import copy | 5 import copy |
6 import json | 6 import json |
7 import tarfile | 7 import tarfile |
8 | 8 |
9 from google.appengine.api import memcache | 9 from google.appengine.api import memcache |
10 from google.appengine.ext import db | 10 from google.appengine.ext import db |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 """When this package version was created.""" | 65 """When this package version was created.""" |
66 | 66 |
67 downloads = db.IntegerProperty(required=True, default=0) | 67 downloads = db.IntegerProperty(required=True, default=0) |
68 """The number of times this package version has been downloaded.""" | 68 """The number of times this package version has been downloaded.""" |
69 | 69 |
70 sort_order = db.IntegerProperty(default=-1) | 70 sort_order = db.IntegerProperty(default=-1) |
71 """The sort order for this version. | 71 """The sort order for this version. |
72 | 72 |
73 Lower numbers indicate earlier versions.""" | 73 Lower numbers indicate earlier versions.""" |
74 | 74 |
75 uploader = db.UserProperty(required=True) | 75 uploaderEmail = db.StringProperty(required=True) |
76 """The user who uploaded this package version.""" | |
77 | |
78 uploaderEmail = db.StringProperty() | |
79 """The user email who uploaded this package version.""" | 76 """The user email who uploaded this package version.""" |
80 | 77 |
81 def temp_synchronize_uploader_to_uploaderemail_and_pickles(self): | |
82 """ Will synchronize properties. | |
83 | |
84 uploader/readme/changelog -> uploaderEmail/readmeString/changelogString | |
85 """ | |
86 if self.uploader is None: | |
87 self.uploaderEmail = None | |
88 else: | |
89 self.uploaderEmail = self.uploader.email() | |
90 | |
91 if self.readme: | |
92 self.readmeFilename = self.readme.filename | |
93 self.readmeContent = db.Text(self.readme.text) | |
94 | |
95 if self.changelog: | |
96 self.changelogFilename = self.changelog.filename | |
97 self.changelogContent = db.Text(self.changelog.text) | |
98 | |
99 @property | 78 @property |
100 def readme_obj(self): | 79 def readme_obj(self): |
101 if self.readmeFilename: | 80 if self.readmeFilename: |
102 return Readme(self.readmeContent, self.readmeFilename) | 81 return Readme(self.readmeContent, self.readmeFilename) |
103 else: | 82 else: |
104 return None | 83 return None |
105 | 84 |
106 @property | 85 @property |
107 def changelog_obj(self): | 86 def changelog_obj(self): |
108 if self.readmeFilename: | 87 if self.changelogFilename: |
109 return Readme(self.changelogContent, self.changelogFilename) | 88 return Readme(self.changelogContent, self.changelogFilename) |
110 else: | 89 else: |
111 return None | 90 return None |
112 | 91 |
113 @classmethod | 92 @classmethod |
114 def new(cls, **kwargs): | 93 def new(cls, **kwargs): |
115 """Construct a new package version. | 94 """Construct a new package version. |
116 | 95 |
117 Unlike __init__, this infers some properties from others. In particular: | 96 Unlike __init__, this infers some properties from others. In particular: |
118 | 97 |
119 - The version is inferred from the pubspec. | 98 - The version is inferred from the pubspec. |
120 - The key name is set to the version. | 99 - The key name is set to the version. |
121 - The parent entity is set to the package. | 100 - The parent entity is set to the package. |
122 """ | 101 """ |
123 | 102 |
124 if 'pubspec' in kwargs and 'version' not in kwargs: | 103 if 'pubspec' in kwargs and 'version' not in kwargs: |
125 kwargs['version'] = kwargs['pubspec'].required('version') | 104 kwargs['version'] = kwargs['pubspec'].required('version') |
126 | 105 |
127 if 'version' in kwargs and \ | 106 if 'version' in kwargs and \ |
128 not isinstance(kwargs['version'], SemanticVersion): | 107 not isinstance(kwargs['version'], SemanticVersion): |
129 kwargs['version'] = SemanticVersion(kwargs['version']) | 108 kwargs['version'] = SemanticVersion(kwargs['version']) |
130 | 109 |
| 110 if 'readme' in kwargs and kwargs['readme']: |
| 111 kwargs['readmeFilename'] = kwargs['readme'].filename |
| 112 kwargs['readmeContent'] = kwargs['readme'].text |
| 113 del kwargs['readme'] |
| 114 |
| 115 if 'changelog' in kwargs and kwargs['changelog']: |
| 116 kwargs['changelogFilename'] = kwargs['changelog'].filename |
| 117 kwargs['changelogContent'] = kwargs['changelog'].text |
| 118 del kwargs['changelog'] |
| 119 |
131 if not 'key_name' in kwargs and not 'key' in kwargs: | 120 if not 'key_name' in kwargs and not 'key' in kwargs: |
132 kwargs['key_name'] = str(kwargs['version'].canonical) | 121 kwargs['key_name'] = str(kwargs['version'].canonical) |
133 | 122 |
134 if not 'parent' in kwargs: | 123 if not 'parent' in kwargs: |
135 kwargs['parent'] = kwargs['package'] | 124 kwargs['parent'] = kwargs['package'] |
136 | 125 |
137 version = cls(**kwargs) | 126 version = cls(**kwargs) |
138 version._validate_fields_match_pubspec() | 127 version._validate_fields_match_pubspec() |
139 return version | 128 return version |
140 | 129 |
141 # TODO(kustermann): When we have string emails, this needs to be changed | |
142 # to read uploaderEmails instead of uploaders. | |
143 @classmethod | 130 @classmethod |
144 def from_archive(cls, file, uploader): | 131 def from_archive(cls, file, uploaderEmail): |
145 """Load a package version from a .tar.gz archive. | 132 """Load a package version from a .tar.gz archive. |
146 | 133 |
147 If the package specified in the archive already exists, it will be | 134 If the package specified in the archive already exists, it will be |
148 loaded and assigned as the package version's package. If it doesn't, a | 135 loaded and assigned as the package version's package. If it doesn't, a |
149 new package will be created. | 136 new package will be created. |
150 | 137 |
151 Arguments: | 138 Arguments: |
152 file: An open file object containing a .tar.gz archive. | 139 file: An open file object containing a .tar.gz archive. |
153 uploader: The user who uploaded this package archive. | 140 uploaderEmail: The user email who uploaded this package archive. |
154 | 141 |
155 Returns: Both the Package object and the PackageVersion object. | 142 Returns: Both the Package object and the PackageVersion object. |
156 """ | 143 """ |
157 try: | 144 try: |
158 tar = tarfile.open(mode="r:gz", fileobj=file) | 145 tar = tarfile.open(mode="r:gz", fileobj=file) |
159 changelog = Readme.from_archive(tar, name='CHANGELOG') | 146 changelog = Readme.from_archive(tar, name='CHANGELOG') |
160 readme = Readme.from_archive(tar) | 147 readme = Readme.from_archive(tar) |
161 pubspec = Pubspec.from_archive(tar) | 148 pubspec = Pubspec.from_archive(tar) |
162 name = pubspec.required('name') | 149 name = pubspec.required('name') |
163 package = Package.get_by_key_name(name) | 150 package = Package.get_by_key_name(name) |
164 if not package: | 151 if not package: |
165 assert uploader is not None | 152 assert uploaderEmail is not None |
166 package = Package.new(name=name, uploaders=[uploader]) | 153 package = Package.new(name=name, uploaderEmails=[uploaderEmail]) |
167 | 154 |
168 libraries = sorted(name[4:] for name in tar.getnames() | 155 libraries = sorted(name[4:] for name in tar.getnames() |
169 if name.startswith('lib/') and | 156 if name.startswith('lib/') and |
170 not name.startswith('lib/src/') and | 157 not name.startswith('lib/src/') and |
171 name.endswith('.dart')) | 158 name.endswith('.dart')) |
172 | 159 |
173 return PackageVersion.new( | 160 return PackageVersion.new( |
174 package=package, changelog=changelog, readme=readme, | 161 package=package, changelog=changelog, readme=readme, |
175 pubspec=pubspec, libraries=libraries, uploader=uploader) | 162 pubspec=pubspec, libraries=libraries, |
| 163 uploaderEmail=uploaderEmail) |
176 except (tarfile.TarError, KeyError) as err: | 164 except (tarfile.TarError, KeyError) as err: |
177 raise db.BadValueError( | 165 raise db.BadValueError( |
178 "Error parsing package archive: %s" % err) | 166 "Error parsing package archive: %s" % err) |
179 | 167 |
180 @classmethod | 168 @classmethod |
181 def get_by_name_and_version(cls, package_name, version): | 169 def get_by_name_and_version(cls, package_name, version): |
182 """Looks up a package version by its package name and version.""" | 170 """Looks up a package version by its package name and version.""" |
183 parent_key = db.Key.from_path('Package', package_name) | 171 parent_key = db.Key.from_path('Package', package_name) |
184 return cls.get_by_key_name( | 172 return cls.get_by_key_name( |
185 SemanticVersion(version).canonical, parent=parent_key) | 173 SemanticVersion(version).canonical, parent=parent_key) |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 'Version "%s" in pubspec doesn\'t match version "%s"' % | 284 'Version "%s" in pubspec doesn\'t match version "%s"' % |
297 (version_in_pubspec._key(), self.version._key())) | 285 (version_in_pubspec._key(), self.version._key())) |
298 @property | 286 @property |
299 def url(self): | 287 def url(self): |
300 """The API URL for this package version.""" | 288 """The API URL for this package version.""" |
301 return models.url(controller='api.versions', | 289 return models.url(controller='api.versions', |
302 action='show', | 290 action='show', |
303 package_id=self.package.name, | 291 package_id=self.package.name, |
304 id=str(self.version)) | 292 id=str(self.version)) |
305 | 293 |
306 # TODO(kustermann): When we have string emails, this needs to be changed | |
307 # to read uploaderEmails instead of uploaders. | |
308 def as_dict(self, full=False): | 294 def as_dict(self, full=False): |
309 """Returns the dictionary representation of this package version. | 295 """Returns the dictionary representation of this package version. |
310 | 296 |
311 This is used to represent the package in API responses. Normally this | 297 This is used to represent the package in API responses. Normally this |
312 just includes URLs and the pubspec, but if full is True, it will include | 298 just includes URLs and the pubspec, but if full is True, it will include |
313 all available information about the package version. | 299 all available information about the package version. |
314 """ | 300 """ |
315 | 301 |
316 value = { | 302 value = { |
317 'version': str(self.version), | 303 'version': str(self.version), |
(...skipping 12 matching lines...) Expand all Loading... |
330 | 316 |
331 if full: | 317 if full: |
332 value.update({ | 318 value.update({ |
333 'created': self.created.isoformat(), | 319 'created': self.created.isoformat(), |
334 'downloads': self.downloads, | 320 'downloads': self.downloads, |
335 'libraries': self.libraries, | 321 'libraries': self.libraries, |
336 'uploader': self.uploaderEmail | 322 'uploader': self.uploaderEmail |
337 }) | 323 }) |
338 | 324 |
339 return value | 325 return value |
OLD | NEW |