Skip to content

Commit ec02aad

Browse files
committed
Fixed #349
* Format the key ordering in the generated ABOUT file. The current ordering is: about_resource name version <-- if any and the rest is the order from the mapping.config file (if any); otherwise alphabetical order. Signed-off-by: Chin Yeung Li <[email protected]>
1 parent 17e2f22 commit ec02aad

File tree

8 files changed

+97
-30
lines changed

8 files changed

+97
-30
lines changed

docs/CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* New UrlListField introduced for list of urls
66
* The UrlField is now only taking single URL value
77
* The owner is now a StringField instead of ListField
8+
* Format the ordering of the genreated ABOUT file (See https://github.com/nexB/aboutcode-toolkit/issues/349#issuecomment-438871444)
89

910

1011
2018-10-23

src/attributecode/gen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ def generate(location, base_dir, license_notice_text_location=None,
302302
about.license_name.present = True
303303

304304
# Write the ABOUT files
305-
about.dump(dump_loc, with_empty=with_empty, with_absent=with_absent)
305+
about.dump(dump_loc, use_mapping=use_mapping, mapping_file=mapping_file, with_empty=with_empty, with_absent=with_absent)
306306
for e in not_exist_errors:
307307
errors.append(Error(ERROR, e))
308308
except Exception as e:

src/attributecode/model.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ def load_dict(self, fields_dict, base_dir, running_inventory=False,
10911091
return errors
10921092

10931093

1094-
def dumps(self, with_absent=False, with_empty=True):
1094+
def dumps(self, use_mapping=False, mapping_file=False, with_absent=False, with_empty=True):
10951095
"""
10961096
Return self as a formatted ABOUT string.
10971097
If with_absent, include absent (not present) fields.
@@ -1138,9 +1138,10 @@ def dumps(self, with_absent=False, with_empty=True):
11381138
if lic_group[3]:
11391139
lic_dict['url'] = lic_group[3]
11401140
about_data.setdefault('licenses', []).append(lic_dict)
1141-
return saneyaml.dump(about_data)
1141+
formatted_about_data = util.format_output(about_data, use_mapping, mapping_file)
1142+
return saneyaml.dump(formatted_about_data)
11421143

1143-
def dump(self, location, with_absent=False, with_empty=True):
1144+
def dump(self, location, use_mapping=False, mapping_file=False, with_absent=False, with_empty=True):
11441145
"""
11451146
Write formatted ABOUT representation of self to location.
11461147
If with_absent, include absent (not present) fields.
@@ -1160,7 +1161,7 @@ def dump(self, location, with_absent=False, with_empty=True):
11601161
if on_windows:
11611162
about_file_path = add_unc(about_file_path)
11621163
with codecs.open(about_file_path, mode='wb', encoding='utf-8') as dumped:
1163-
dumped.write(self.dumps(with_absent, with_empty))
1164+
dumped.write(self.dumps(use_mapping, mapping_file, with_absent, with_empty))
11641165

11651166
def dump_lic(self, location, license_dict):
11661167
"""

src/attributecode/util.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ def get_mapping(location=None):
330330
if not os.path.exists(location):
331331
return {}
332332

333-
mapping = {}
333+
mapping = collections.OrderedDict()
334334
try:
335335
with open(location) as mapping_file:
336336
for line in mapping_file:
@@ -412,6 +412,52 @@ def apply_mapping(abouts, alternate_mapping=None):
412412
mapped_abouts.append(mapped_about)
413413
return mapped_abouts
414414

415+
def get_mapping_key_order(mapping_file):
416+
"""
417+
Get the mapping key order and return as a list
418+
"""
419+
if mapping_file:
420+
mapping = get_mapping(mapping_file)
421+
else:
422+
mapping = get_mapping()
423+
return mapping.keys()
424+
425+
def format_output(about_data, use_mapping, mapping_file):
426+
"""
427+
Convert the about_data dictionary to an ordered dictionary for saneyaml.dump()
428+
The ordering should be:
429+
430+
about_resource
431+
name
432+
version <-- if any
433+
and the rest is the order from the mapping.config file (if any); otherwise alphabetical order.
434+
"""
435+
mapping_key_order = []
436+
if use_mapping or mapping_file:
437+
mapping_key_order = get_mapping_key_order(mapping_file)
438+
priority_keys = [u'about_resource', u'name', u'version']
439+
about_data_keys = []
440+
order_dict = collections.OrderedDict()
441+
for key in about_data:
442+
about_data_keys.append(key)
443+
if u'about_resource' in about_data_keys:
444+
order_dict['about_resource'] = about_data['about_resource']
445+
if u'name' in about_data_keys:
446+
order_dict['name'] = about_data['name']
447+
if u'version' in about_data_keys:
448+
order_dict['version'] = about_data['version']
449+
if not mapping_key_order:
450+
for other_key in sorted(about_data_keys):
451+
if not other_key in priority_keys:
452+
order_dict[other_key] = about_data[other_key]
453+
else:
454+
for key in mapping_key_order:
455+
if not key in priority_keys and key in about_data_keys:
456+
order_dict[key] = about_data[key]
457+
for other_key in sorted(about_data_keys):
458+
if not other_key in priority_keys and not other_key in mapping_key_order:
459+
order_dict[other_key] = about_data[other_key]
460+
return order_dict
415461

416462
def get_about_file_path(location, use_mapping=False, mapping_file=None):
417463
"""

tests/test_gen.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ def test_load_inventory(self):
6262
assert expected_errors == errors
6363

6464
expected = [u'about_resource: .\n'
65+
u'name: AboutCode\n'
66+
u'version: 0.11.0\n'
6567
u'description: |-\n'
6668
u' multi\n'
67-
u' line\n'
68-
u'name: AboutCode\n'
69-
u'version: 0.11.0\n']
70-
result = [a.dumps(with_absent=False, with_empty=False)
69+
u' line\n']
70+
result = [a.dumps(use_mapping=False, mapping_file=False, with_absent=False, with_empty=False)
7171
for a in abouts]
7272
assert expected == result
7373

@@ -86,15 +86,15 @@ def test_load_inventory_with_mapping(self):
8686
assert sorted(expected_errors) == sorted(errors)
8787

8888
expected = [u'about_resource: .\n'
89+
u'name: AboutCode\n'
90+
u'version: 0.11.0\n'
8991
u'copyright: Copyright (c) nexB, Inc.\n'
92+
u'resource: this.ABOUT\n'
9093
u'description: |-\n'
9194
u' multi\n'
9295
u' line\n'
93-
u'name: AboutCode\n'
94-
u'resource: this.ABOUT\n'
95-
u'version: 0.11.0\n'
9696
]
97-
result = [a.dumps(with_absent=False, with_empty=False)
97+
result = [a.dumps(use_mapping, mapping_file=False, with_absent=False, with_empty=False)
9898
for a in abouts]
9999
assert expected == result
100100

@@ -148,15 +148,15 @@ def test_generate(self):
148148
assert msg1 in errors[0].message
149149
assert msg2 in errors[1].message
150150

151-
in_mem_result = [a.dumps(with_absent=False, with_empty=False)
151+
in_mem_result = [a.dumps(use_mapping=False, mapping_file=False, with_absent=False, with_empty=False)
152152
for a in abouts][0]
153153
expected = (u'about_resource: .\n'
154+
u'name: AboutCode\n'
155+
u'version: 0.11.0\n'
154156
u'about_resource_path: .\n'
155157
u'description: |-\n'
156158
u' multi\n'
157-
u' line\n'
158-
u'name: AboutCode\n'
159-
u'version: 0.11.0\n')
159+
u' line\n')
160160
assert expected == in_mem_result
161161

162162
def test_generate_not_overwrite_original_license_file(self):
@@ -167,14 +167,14 @@ def test_generate_not_overwrite_original_license_file(self):
167167

168168
errors, abouts = gen.generate(location, base_dir, license_notice_text_location, fetch_license)
169169

170-
in_mem_result = [a.dumps(with_absent=False, with_empty=False)
170+
in_mem_result = [a.dumps(use_mapping=False, mapping_file=False, with_absent=False, with_empty=False)
171171
for a in abouts][0]
172172
expected = (u'about_resource: .\n'
173+
u'name: AboutCode\n'
174+
u'version: 0.11.0\n'
173175
u'about_resource_path: .\n'
174176
u'licenses:\n'
175-
u' - file: this.LICENSE\n'
176-
u'name: AboutCode\n'
177-
u'version: 0.11.0\n')
177+
u' - file: this.LICENSE\n')
178178
assert expected == in_mem_result
179179

180180
def test_deduplicate(self):

tests/test_model.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -707,29 +707,29 @@ def test_About_dumps(self):
707707
assert [] == a.errors
708708

709709
expected = u'''about_resource: .
710+
name: AboutCode
711+
version: 0.11.0
712+
copyright: Copyright (c) 2013-2014 nexB Inc.
713+
license_expression: apache-2.0
710714
author:
711715
- Jillian Daguil
712716
- Chin Yeung Li
713717
- Philippe Ombredanne
714718
- Thomas Druez
715-
copyright: Copyright (c) 2013-2014 nexB Inc.
716719
description: |-
717720
AboutCode is a tool
718721
to process ABOUT files.
719722
An ABOUT file is a file.
720723
homepage_url: http://dejacode.org
721-
license_expression: apache-2.0
722724
licenses:
723725
- file: apache-2.0.LICENSE
724726
key: apache-2.0
725-
name: AboutCode
726727
notice_file: NOTICE
727728
owner: nexB Inc.
728729
vcs_repository: https://github.com/dejacode/about-code-tool.git
729730
vcs_tool: git
730-
version: 0.11.0
731731
'''
732-
result = a.dumps()
732+
result = a.dumps(use_mapping=True)
733733
assert expected == result
734734

735735
# We do not support with_absent and with_empty staring in version 3.2.0.
@@ -811,7 +811,7 @@ def test_About_dumps_with_different_boolean_value(self):
811811
modified: yes
812812
'''
813813

814-
result = a.dumps()
814+
result = a.dumps(use_mapping=False, mapping_file=False)
815815
assert set(expected) == set(result)
816816

817817

@@ -827,7 +827,7 @@ def test_About_dumps_does_not_dump_present__empty_with_absent_False(self):
827827
name: AboutCode
828828
version: 0.11.0
829829
'''
830-
result = a.dumps(with_absent=False, with_empty=False)
830+
result = a.dumps(use_mapping=False, mapping_file=False, with_absent=False, with_empty=False)
831831
assert expected == result
832832

833833
def test_About_as_dict_contains_special_paths(self):
@@ -940,7 +940,7 @@ def test_load_dump_is_idempotent(self):
940940
a = model.About()
941941
a.load(test_file)
942942
dumped_file = get_temp_file('that.ABOUT')
943-
a.dump(dumped_file, with_absent=False, with_empty=False)
943+
a.dump(dumped_file, use_mapping=False, mapping_file=False, with_absent=False, with_empty=False)
944944

945945
expected = get_unicode_content(test_file).splitlines()
946946
result = get_unicode_content(dumped_file).splitlines()

tests/test_util.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,17 @@ def test_get_relative_path_with_same_path_twice(self):
266266
result = util.get_relative_path(loc, loc)
267267
assert expected == result
268268

269+
def test_get_mapping_key_order(self):
270+
expected = ['about_file_path', 'name', 'version', 'copyright', 'license_expression', 'resource']
271+
result = util.get_mapping_key_order(mapping_file=False)
272+
assert expected == result
273+
274+
def test_get_mapping_key_order_with_mapping_file(self):
275+
expected = ['about_file_path', 'name', 'version', 'description', 'license_expression', 'copyright']
276+
test_mapping_file = get_test_loc('mapping_config/mapping.config')
277+
result = util.get_mapping_key_order(test_mapping_file)
278+
assert expected == result
279+
269280
def test_load_csv_without_mapping(self):
270281
test_file = get_test_loc('util/about.csv')
271282
expected = [OrderedDict(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
about_file_path: about_file
2+
name: Component
3+
version: Confirmed Version
4+
5+
# Optional Fields
6+
description: description
7+
license_expression: dje_license_key
8+
copyright: Confirmed Copyright

0 commit comments

Comments
 (0)