Skip to content

Commit b456d9a

Browse files
committed
add packaged code to handle podspec
Signed-off-by: rpotter12 <rohitpotter12@gmail.com>
1 parent 0722eec commit b456d9a

3 files changed

Lines changed: 199 additions & 4 deletions

File tree

src/packagedcode/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@
2525
from __future__ import absolute_import
2626
from __future__ import unicode_literals
2727

28-
from packagedcode import build
29-
from packagedcode import chef
30-
from packagedcode import models
3128
from packagedcode import about
3229
from packagedcode import bower
33-
from packagedcode import conda
30+
from packagedcode import build
3431
from packagedcode import cargo
32+
from packagedcode import chef
33+
from packagedcode import conda
34+
from packagedcode import cocoapods
3535
from packagedcode import freebsd
3636
from packagedcode import haxe
3737
from packagedcode import maven
38+
from packagedcode import models
3839
from packagedcode import npm
3940
from packagedcode import nuget
4041
from packagedcode import phpcomposer
@@ -62,6 +63,7 @@
6263
phpcomposer.PHPComposerPackage,
6364
haxe.HaxePackage,
6465
cargo.RustCargoCrate,
66+
cocoapods.CocoapodsPackage,
6567
models.MeteorPackage,
6668
bower.BowerPackage,
6769
freebsd.FreeBSDPackage,

src/packagedcode/cocoapods.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/scancode-toolkit/
3+
# The ScanCode software is licensed under the Apache License version 2.0.
4+
# Data generated with ScanCode require an acknowledgment.
5+
# ScanCode is a trademark of nexB Inc.
6+
#
7+
# You may not use this software except in compliance with the License.
8+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
9+
# Unless required by applicable law or agreed to in writing, software distributed
10+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
# specific language governing permissions and limitations under the License.
13+
#
14+
# When you publish or redistribute any data created with ScanCode or any ScanCode
15+
# derivative work, you must accompany this data with the following acknowledgment:
16+
#
17+
# Generated with ScanCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
18+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
19+
# ScanCode should be considered or used as legal advice. Consult an Attorney
20+
# for any legal advice.
21+
# ScanCode is a free software code scanning tool from nexB Inc. and others.
22+
# Visit https://github.com/nexB/scancode-toolkit/ for support and download.
23+
24+
from __future__ import absolute_import
25+
from __future__ import print_function
26+
from __future__ import unicode_literals
27+
28+
import logging
29+
import re
30+
31+
import attr
32+
from packageurl import PackageURL
33+
34+
from commoncode.fileutils import py2
35+
from commoncode import filetype
36+
from commoncode import fileutils
37+
from packagedcode import models
38+
from packagedcode.spec import ParseSpec
39+
40+
41+
"""
42+
Handle cocoapods packages manifests for macOS and iOS
43+
including .podspec, Podfile and Podfile.lock files.
44+
See https://cocoapods.org
45+
"""
46+
47+
# TODO: implementation to get dependency data using gemsfileparser
48+
# Check: https://gitlab.com/balasankarc/gemfileparser
49+
# TODO: override the license detection to detect declared_license correctly.
50+
51+
52+
TRACE = False
53+
54+
logger = logging.getLogger(__name__)
55+
56+
if TRACE:
57+
import sys
58+
logging.basicConfig(stream=sys.stdout)
59+
logger.setLevel(logging.DEBUG)
60+
61+
62+
@attr.s()
63+
class CocoapodsPackage(models.Package):
64+
metafiles = ('*.podspec',)
65+
extensions = ('.podspec',)
66+
default_type = 'pods'
67+
default_primary_language = 'Objective-C'
68+
default_web_baseurl = 'https://cocoapods.org'
69+
default_download_baseurl = None
70+
default_api_baseurl = None
71+
72+
@classmethod
73+
def recognize(cls, location):
74+
yield parse(location)
75+
76+
def repository_homepage_url(self, baseurl=default_web_baseurl):
77+
return '{}/pods/{}'.format(baseurl, self.name)
78+
79+
def repository_download_url(self):
80+
return '{}/archive/{}.zip'.format(self.homepage_url, self.version)
81+
82+
83+
def is_podspec(location):
84+
"""
85+
Checks if the file is actually a podspec file
86+
"""
87+
return (filetype.is_file(location) and location.endswith('.podspec'))
88+
89+
90+
def parse(location):
91+
"""
92+
Return a Package object from a .podspec file or None.
93+
"""
94+
if not is_podspec(location):
95+
return
96+
97+
podspec_obj = ParseSpec()
98+
podspec_data = podspec_obj.parse_spec(location)
99+
return build_package(podspec_data)
100+
101+
102+
def build_package(podspec_data):
103+
"""
104+
Return a Package object from a package data mapping or None.
105+
"""
106+
name = podspec_data.get('name')
107+
version = podspec_data.get('version')
108+
declared_license = podspec_data.get('license')
109+
summary = podspec_data.get('summary')
110+
description = podspec_data.get('description')
111+
homepage_url = podspec_data.get('homepage_url')
112+
source = podspec_data.get('source')
113+
authors = podspec_data.get('author') or None
114+
115+
author_names = []
116+
author_email = []
117+
if authors:
118+
for split_author in authors:
119+
split_author = split_author.strip()
120+
author, email = parse_person(split_author)
121+
author_names.append(author)
122+
author_email.append(email)
123+
124+
parties = []
125+
if authors:
126+
parties.append(
127+
models.Party(
128+
type=models.party_person,
129+
name=', '.join(author_names),
130+
email=', '.join(author_email),
131+
role='author'
132+
)
133+
)
134+
135+
if len(summary) > len(description):
136+
description = summary
137+
138+
package = CocoapodsPackage(
139+
name=name,
140+
version=version,
141+
vcs_url=source,
142+
source_packages=list(source.split('\n')),
143+
description=description,
144+
declared_license=declared_license,
145+
homepage_url=homepage_url,
146+
parties=parties
147+
)
148+
return package
149+
150+
151+
person_parser = re.compile(
152+
r'^(?P<name>[\w\s(),-_.,]+)'
153+
r'=>'
154+
r'(?P<email>[\S+]+$)'
155+
).match
156+
157+
person_parser_only_name = re.compile(
158+
r'^(?P<name>[\w\s(),-_.,]+)'
159+
).match
160+
161+
162+
def parse_person(person):
163+
"""
164+
Return name and email from person string.
165+
166+
https://guides.cocoapods.org/syntax/podspec.html#authors
167+
Author can be in the form:
168+
s.author = 'Rohit Potter'
169+
or
170+
s.author = 'Rohit Potter=>rohit@gmail.com'
171+
Author check:
172+
>>> p = parse_person('Rohit Potter=>rohit@gmail.com')
173+
>>> assert p == ('Rohit Potter', 'rohit@gmail.com')
174+
>>> p = parse_person('Rohit Potter')
175+
>>> assert p == ('Rohit Potter', None)
176+
"""
177+
parsed = person_parser(person)
178+
if not parsed:
179+
parsed = person_parser_only_name(person)
180+
name = parsed.group('name')
181+
email = None
182+
else:
183+
name = parsed.group('name')
184+
email = parsed.group('email')
185+
186+
return name, email

tests/packagedcode/data/plugin/help.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,13 @@ Package: nuget
200200
extensions: .nupkg
201201
filetypes: zip archive, microsoft ooxml
202202

203+
204+
--------------------------------------------
205+
Package: pods
206+
class: packagedcode.cocoapods:CocoapodsPackage
207+
metafiles: *.podspec
208+
extensions: .podspec
209+
203210
--------------------------------------------
204211
Package: pypi
205212
class: packagedcode.pypi:PythonPackage

0 commit comments

Comments
 (0)