<s> from __future__ import unicode_literals <EOL> import os <EOL> import json <EOL> from semantic_version import Version <EOL> import frappe <EOL> from frappe . utils import cstr <EOL> def get_change_log ( user = None ) : <EOL> if not user : user = frappe . session . user <EOL> last_known_versions = frappe . _dict ( json . loads ( frappe . db . get_value ( "<STR_LIT>" , <EOL> user , "<STR_LIT>" ) or "<STR_LIT:{}>" ) ) <EOL> current_versions = get_versions ( ) <EOL> if not last_known_versions : <EOL> update_last_known_versions ( ) <EOL> return [ ] <EOL> change_log = [ ] <EOL> def set_in_change_log ( app , opts , change_log ) : <EOL> from_version = last_known_versions . get ( app , { } ) . get ( "<STR_LIT:version>" ) or "<STR_LIT>" <EOL> to_version = opts [ "<STR_LIT:version>" ] <EOL> if from_version != to_version : <EOL> app_change_log = get_change_log_for_app ( app , from_version = from_version , to_version = to_version ) <EOL> if app_change_log : <EOL> change_log . append ( { <EOL> "<STR_LIT:title>" : opts [ "<STR_LIT:title>" ] , <EOL> "<STR_LIT:description>" : opts [ "<STR_LIT:description>" ] , <EOL> "<STR_LIT:version>" : to_version , <EOL> "<STR_LIT>" : app_change_log <EOL> } ) <EOL> for app , opts in current_versions . items ( ) : <EOL> if app != "<STR_LIT>" : <EOL> set_in_change_log ( app , opts , change_log ) <EOL> if "<STR_LIT>" in current_versions : <EOL> set_in_change_log ( "<STR_LIT>" , current_versions [ "<STR_LIT>" ] , change_log ) <EOL> return change_log <EOL> def get_change_log_for_app ( app , from_version , to_version ) : <EOL> change_log_folder = os . path . join ( frappe . get_app_path ( app ) , "<STR_LIT>" ) <EOL> if not os . path . exists ( change_log_folder ) : <EOL> return <EOL> from_version = Version ( from_version ) <EOL> to_version = Version ( to_version ) <EOL> to_version . prerelease = None <EOL> major_version_folders = [ "<STR_LIT>" . format ( i ) for i in xrange ( from_version . major , to_version . major + <NUM_LIT:1> ) ] <EOL> app_change_log = [ ] <EOL> for folder in os . listdir ( change_log_folder ) : <EOL> if folder in major_version_folders : <EOL> for file in os . listdir ( os . path . join ( change_log_folder , folder ) ) : <EOL> version = Version ( os . path . splitext ( file ) [ <NUM_LIT:0> ] [ <NUM_LIT:1> : ] . replace ( "<STR_LIT:_>" , "<STR_LIT:.>" ) ) <EOL> if from_version < version <= to_version : <EOL> file_path = os . path . join ( change_log_folder , folder , file ) <EOL> content = frappe . read_file ( file_path ) <EOL> app_change_log . append ( [ version , content ] ) <EOL> app_change_log = sorted ( app_change_log , key = lambda d : d [ <NUM_LIT:0> ] , reverse = True ) <EOL> return [ [ cstr ( d [ <NUM_LIT:0> ] ) , d [ <NUM_LIT:1> ] ] for d in app_change_log ] <EOL> @ frappe . whitelist ( ) <EOL> def update_last_known_versions ( ) : <EOL> frappe . db . set_value ( "<STR_LIT>" , frappe . session . user , "<STR_LIT>" , <EOL> json . dumps ( get_versions ( ) ) , update_modified = False ) <EOL> @ frappe . whitelist ( ) <EOL> def get_versions ( ) : <EOL> """<STR_LIT>""" <EOL> versions = { } <EOL> for app in frappe . get_installed_apps ( sort = True ) : <EOL> versions [ app ] = { <EOL> "<STR_LIT:title>" : frappe . get_hooks ( "<STR_LIT>" , app_name = app ) [ <NUM_LIT:0> ] , <EOL> "<STR_LIT:description>" : frappe . get_hooks ( "<STR_LIT>" , app_name = app ) [ <NUM_LIT:0> ] <EOL> } <EOL> try : <EOL> versions [ app ] [ "<STR_LIT:version>" ] = frappe . get_attr ( app + "<STR_LIT>" ) <EOL> except AttributeError : <EOL> versions [ app ] [ "<STR_LIT:version>" ] = '<STR_LIT>' <EOL> return versions </s>
