2626from os .path import exists , dirname , join , abspath , isdir
2727import about
2828import csv
29+ import copy
2930import errno
31+ import json
3032import getopt
3133import os
3234import shutil
3335import sys
36+ import urllib
37+ import urllib2
38+
3439
3540__version__ = '0.9.0'
3641
4348self_path = abspath (dirname (__file__ ))
4449
4550
51+ def request_license_data (url , username , api_key , license_key ):
52+ """
53+ Send a request to a given API URL to gather license data.
54+ Authentication through an Api Key and a username.
55+ Returns a python dictionary of results returned by the API.
56+ """
57+ payload = {
58+ 'username' : username ,
59+ 'api_key' : api_key ,
60+ 'format' : 'json'
61+ }
62+
63+ full_url = '{0}{1}/?{2}' .format (
64+ url if url .endswith ('/' ) else url + '/' ,
65+ license_key , urllib .urlencode (payload ))
66+
67+ request = urllib2 .Request (full_url )
68+ try :
69+ response = urllib2 .urlopen (request )
70+ response_content = response .read ()
71+ data = json .loads (response_content )
72+ except (urllib2 .HTTPError , ValueError ):
73+ return {}
74+ else :
75+ return data
76+
77+
4678class GenAbout (object ):
4779 def __init__ (self ):
4880 self .warnings = []
@@ -162,7 +194,7 @@ def verify_license_files(self, input_list, project_path):
162194
163195 def copy_license_files (self , gen_location , license_list ):
164196 """
165- copy the 'license_text_file' into the gen_location
197+ Copy the 'license_text_file' into the gen_location
166198 """
167199 for items in license_list :
168200 license_path = items [0 ]
@@ -174,19 +206,72 @@ def copy_license_files(self, gen_location, license_list):
174206 makedirs (license_parent_dir )
175207 shutil .copy2 (license_path , output_license_path )
176208
177- #def extract_license_from_url(self):
178- # # This function needs discussion
179- # test = urllib2.urlopen("https://enterprise.dejacode.com/license_library/Demo/gpl-1.0/#license-text")
180- # with open('testdata/test_file.txt', 'wb') as output_file:
181- # output_file.write(test.read())
209+ def get_dje_license_key (self , input_list ):
210+ """
211+ Get the DJE License Keys
212+ """
213+ output_list = []
214+ for component in input_list :
215+ for line in component :
216+ try :
217+ if line ['dje_license_key' ]:
218+ dje_license_key_list = []
219+ dje_key = line ['dje_license_key' ]
220+ file_location = line ['about_file' ]
221+ if file_location .endswith ('/' ):
222+ file_location = file_location .rpartition ('/' )[0 ]
223+ about_parent_dir = os .path .dirname (file_location )
224+ dje_license_key_list .append (about_parent_dir )
225+ dje_license_key_list .append (dje_key )
226+ output_list .append (dje_license_key_list )
227+ else :
228+ self .warnings .append (Warn ('dje_license_key' , '' ,
229+ "No 'dje_license_key' for " + line ['about_file' ]))
230+ except Exception as e :
231+ print (repr (e ))
232+ print ("The input does not have the 'dje_license_key' key which is required." )
233+ sys .exit (errno .EINVAL )
234+ return output_list
235+
236+ def extract_dje_license (self , project_path , license_list , url , username , key ):
237+ """
238+ Extract license text from DJE
239+ """
240+ for items in license_list :
241+ gen_path = items [0 ]
242+ license_key = items [1 ]
243+ if '/' in gen_path :
244+ gen_path = gen_path .partition ('/' )[2 ]
245+ gen_license_path = join (project_path , gen_path , license_key ) + '.LICENSE'
246+ context = self .get_license_text_from_api (url , username , key , license_key )
247+ if not context :
248+ self .errors .append (Error ('dje_license_key' , license_key ,
249+ "Invalid 'dje_license_key'" ))
250+ else :
251+ with open (gen_license_path , 'wb' ) as output :
252+ output .write (context )
253+
254+ @staticmethod
255+ def get_license_text_from_api (url , username , api_key , license_key ):
256+ """
257+ Returns the license_text of a given license_key using an API request.
258+ Returns an empty string if the text is not available.
259+ """
260+ data = request_license_data (url , username , api_key , license_key )
261+ license_text = data .get ('full_text' , '' )
262+ return license_text
182263
183264 def pre_generation (self , gen_location , input_list , action_num , all_in_one ):
184265 """
185266 check the existence of the output location and handle differently
186267 according to the action_num.
187268 """
188269 output_list = []
189- for component in input_list :
270+ # The input_list needs to be copied and be used below.
271+ # Otherwise, the value in the input_list may be changed based on the
272+ # action number below
273+ copied_list = copy .deepcopy (input_list )
274+ for component in copied_list :
190275 for line in component :
191276 component_list = []
192277 file_location = line ['about_file' ]
@@ -357,6 +442,15 @@ def option_usage():
357442 <path>
358443 Project path
359444 --mapping Activate the MAPPING.CONFIG
445+ --extract_license <3 args required> Extract License text and create <license_key>.LICENSE
446+ side-by-side with the .ABOUT from DJE License Library
447+ <--api_url='URL'> - URL to the DJE License Library
448+ <--api_username='user_api'> - The regular DJE username
449+ <--api_key='user_api_key'> - Hash attached to your username which is used
450+ to Authenticate yourself in the API. Contact
451+ us to get the hash key.
452+ Example syntax:
453+ genabout.py --extract_license --api_url='https://enterprise.dejacode.com/api/v1/license_text/' --api_username='<user_api>' --api_key='<user_api_key>'
360454""" )
361455
362456
@@ -366,6 +460,10 @@ def main(args, opts):
366460 all_in_one = False
367461 project_path = ''
368462 mapping_config = False
463+ gen_license = False
464+ api_url = ''
465+ api_username = ''
466+ api_key = ''
369467
370468 for opt , opt_arg in opts :
371469 invalid_opt = True
@@ -426,9 +524,41 @@ def main(args, opts):
426524 else :
427525 mapping_config = True
428526
527+ if opt in ('--extract_license' ):
528+ invalid_opt = False
529+ gen_license = True
530+
531+
532+ if opt in ('--api_url' ):
533+ invalid_opt = False
534+ if not opt_arg or not 'http' in opt_arg .lower ():
535+ print ("Invalid option argument." )
536+ option_usage ()
537+ sys .exit (errno .EINVAL )
538+ else :
539+ api_url = opt_arg
540+
541+ if opt in ('--api_username' ):
542+ invalid_opt = False
543+ if not opt_arg or '/' in opt_arg or '\\ ' in opt_arg :
544+ print ("Invalid option argument." )
545+ option_usage ()
546+ sys .exit (errno .EINVAL )
547+ else :
548+ api_username = opt_arg
549+
550+ if opt in ('--api_key' ):
551+ invalid_opt = False
552+ if not opt_arg or '/' in opt_arg or '\\ ' in opt_arg :
553+ print ("Invalid option argument." )
554+ option_usage ()
555+ sys .exit (errno .EINVAL )
556+ else :
557+ api_key = opt_arg
558+
429559 if invalid_opt :
430560 assert False , 'Unsupported option.'
431-
561+
432562 if not len (args ) == 2 :
433563 print ('Input file and generated location parameters are mandatory.' )
434564 syntax ()
@@ -460,10 +590,23 @@ def main(args, opts):
460590 components_list = gen .pre_generation (gen_location , input_list , opt_arg_num , all_in_one )
461591 formatted_output = gen .format_output (components_list )
462592 gen .write_output (formatted_output )
593+
594+ # Check do we have all the required arguments: api_url, api_username, api_key
595+ if gen_license :
596+ if not api_url or not api_username or not api_key :
597+ print ("Missing argument for --extract_license" )
598+ option_usage ()
599+ sys .exit (errno .EINVAL )
600+ else :
601+ dje_license_list = gen .get_dje_license_key (input_list )
602+ gen .extract_dje_license (gen_location , dje_license_list , api_url , api_username , api_key )
603+
604+
463605 gen .warnings_errors_summary (gen_location , verb_arg_num )
464606
465607if __name__ == "__main__" :
466- longopts = ['help' , 'version' , 'action=' , 'verbosity=' , 'all-in-one=' , 'copy_license=' , 'mapping' ]
608+ longopts = ['help' , 'version' , 'action=' , 'verbosity=' , 'all-in-one=' , 'copy_license=' , 'mapping' , 'extract_license' , 'api_url='
609+ , 'api_username=' , 'api_key=' ]
467610 try :
468611 opts , args = getopt .getopt (sys .argv [1 :], 'hv' , longopts )
469612 except Exception as e :
0 commit comments