| 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 |