1313import attr
1414import saneyaml
1515
16+ from commoncode import filetype
17+ from commoncode import fileutils
1618from packagedcode import models
1719from packageurl import PackageURL
1820
3436
3537
3638@attr .s ()
37- class CranPackage (models .Package , models . PackageManifest ):
39+ class CranPackage (models .Package ):
3840 file_patterns = ('DESCRIPTION' ,)
3941 default_type = 'cran'
4042 default_web_baseurl = 'https://cran.r-project.org/package='
4143
42- @classmethod
43- def recognize (cls , location ):
44- yield parse (location )
45-
4644 @classmethod
4745 def get_package_root (cls , manifest_resource , codebase ):
4846 return manifest_resource .parent (codebase )
@@ -51,79 +49,87 @@ def repository_homepage_url(self, baseurl=default_web_baseurl):
5149 return '{}{}' .format (baseurl , self .name )
5250
5351
54- def parse (location ):
55- """
56- Return a Package object from a DESCRIPTION file or None.
57- """
58- yaml_data = get_yaml_data (location )
59- return build_package (yaml_data )
52+ @attr .s ()
53+ class DescriptionFile (CranPackage , models .PackageManifest ):
6054
55+ file_patterns = ('DESCRIPTION' )
6156
62- def build_package (package_data ):
63- """
64- Return a cran Package object from a dictionary yaml data.
65- """
66- name = package_data .get ('Package' )
67- if name :
68- parties = []
69- maintainers = package_data .get ('Maintainer' )
70- if maintainers :
71- for maintainer in maintainers .split (',\n ' ):
72- maintainer_name , maintainer_email = get_party_info (maintainer )
73- if maintainer_name or maintainer_email :
74- parties .append (
75- models .Party (
76- name = maintainer_name ,
77- role = 'maintainer' ,
78- email = maintainer_email ,
57+ @classmethod
58+ def is_manifest (cls , location ):
59+ """
60+ Return True if `location` path is for a Cran DESCRIPTION file.
61+ """
62+ return (filetype .is_file (location )
63+ and fileutils .file_name (location ) == 'DESCRIPTION' )
64+
65+ @classmethod
66+ def recognize (cls , location ):
67+ """
68+ Yield one or more Package manifest objects given a file ``location`` pointing to a
69+ package archive, manifest or similar.
70+ """
71+ package_data = get_yaml_data (location )
72+
73+ name = package_data .get ('Package' )
74+ if name :
75+ parties = []
76+ maintainers = package_data .get ('Maintainer' )
77+ if maintainers :
78+ for maintainer in maintainers .split (',\n ' ):
79+ maintainer_name , maintainer_email = get_party_info (maintainer )
80+ if maintainer_name or maintainer_email :
81+ parties .append (
82+ models .Party (
83+ name = maintainer_name ,
84+ role = 'maintainer' ,
85+ email = maintainer_email ,
86+ )
7987 )
80- )
81- authors = package_data .get ('Author' )
82- if authors :
83- for author in authors .split (',\n ' ):
84- author_name , author_email = get_party_info (author )
85- if author_name or author_email :
86- parties .append (
87- models .Party (
88- name = author_name ,
89- role = 'author' ,
90- email = author_email ,
88+ authors = package_data .get ('Author' )
89+ if authors :
90+ for author in authors .split (',\n ' ):
91+ author_name , author_email = get_party_info (author )
92+ if author_name or author_email :
93+ parties .append (
94+ models .Party (
95+ name = author_name ,
96+ role = 'author' ,
97+ email = author_email ,
98+ )
99+ )
100+ package_dependencies = []
101+ dependencies = package_data .get ('Depends' )
102+ if dependencies :
103+ for dependency in dependencies .split (',\n ' ):
104+ requirement = None
105+ for splitter in ('==' , '>=' , '<=' , '>' , '<' ):
106+ if splitter in dependency :
107+ splits = dependency .split (splitter )
108+ # Replace the package name and keep the relationship and version
109+ # For example: R (>= 2.1)
110+ requirement = dependency .replace (splits [0 ], '' ).strip ().strip (')' ).strip ()
111+ dependency = splits [0 ].strip ().strip ('(' ).strip ()
112+ break
113+ package_dependencies .append (
114+ models .DependentPackage (
115+ purl = PackageURL (
116+ type = 'cran' , name = dependency ).to_string (),
117+ requirement = requirement ,
118+ scope = 'dependencies' ,
119+ is_runtime = True ,
120+ is_optional = False ,
91121 )
92122 )
93- package_dependencies = []
94- dependencies = package_data .get ('Depends' )
95- if dependencies :
96- for dependency in dependencies .split (',\n ' ):
97- requirement = None
98- for splitter in ('==' , '>=' , '<=' , '>' , '<' ):
99- if splitter in dependency :
100- splits = dependency .split (splitter )
101- # Replace the package name and keep the relationship and version
102- # For example: R (>= 2.1)
103- requirement = dependency .replace (splits [0 ], '' ).strip ().strip (')' ).strip ()
104- dependency = splits [0 ].strip ().strip ('(' ).strip ()
105- break
106- package_dependencies .append (
107- models .DependentPackage (
108- purl = PackageURL (
109- type = 'cran' , name = dependency ).to_string (),
110- requirement = requirement ,
111- scope = 'dependencies' ,
112- is_runtime = True ,
113- is_optional = False ,
114- )
115- )
116- package = CranPackage (
117- name = name ,
118- version = package_data .get ('Version' ),
119- description = package_data .get ('Description' , '' ) or package_data .get ('Title' , '' ),
120- declared_license = package_data .get ('License' ),
121- parties = parties ,
122- dependencies = package_dependencies ,
123- # TODO: Let's handle the release date as a Date type
124- # release_date = package_data.get('Date/Publication'),
125- )
126- return package
123+ yield cls (
124+ name = name ,
125+ version = package_data .get ('Version' ),
126+ description = package_data .get ('Description' , '' ) or package_data .get ('Title' , '' ),
127+ declared_license = package_data .get ('License' ),
128+ parties = parties ,
129+ dependencies = package_dependencies ,
130+ # TODO: Let's handle the release date as a Date type
131+ # release_date = package_data.get('Date/Publication'),
132+ )
127133
128134
129135def get_yaml_data (location ):
0 commit comments