@@ -953,16 +953,16 @@ def do_help(self, args, nl_re=nl_re, indent_re=indent_re):
953
953
return 0
954
954
955
955
def do_history (self , args ):
956
- '' """Usage: history designator [skipquiet]
956
+ '' """Usage: history designator [skipquiet] [raw]
957
957
Show the history entries of a designator.
958
958
959
959
A designator is a classname and a nodeid concatenated,
960
960
eg. bug1, user10, ...
961
961
962
- Lists the journal entries viewable by the user for the
963
- node identified by the designator. If skipquiet is the
964
- second argument, journal entries for quiet properties
965
- are not shown .
962
+ Lists the journal entries viewable by the user for the node
963
+ identified by the designator. If skipquiet is added, journal
964
+ entries for quiet properties are not shown. If raw is added,
965
+ the output is the raw representation of the journal entries .
966
966
"""
967
967
968
968
if len (args ) < 1 :
@@ -972,15 +972,181 @@ def do_history(self, args):
972
972
except hyperdb .DesignatorError as message :
973
973
raise UsageError (message )
974
974
975
- skipquiet = False
976
- if len (args ) == 2 :
977
- if args [1 ] != 'skipquiet' :
978
- raise UsageError ("Second argument is not skipquiet" )
979
- skipquiet = True
975
+ valid_args = ['skipquiet' , 'raw' ]
976
+
977
+ if len (args ) >= 2 :
978
+ check = [a for a in args [1 :] if a not in valid_args ]
979
+ if check :
980
+ raise UsageError (
981
+ _ ("Unexpected argument(s): %s. "
982
+ "Expected 'skipquiet' or 'raw'." ) % ", " .join (check ))
983
+
984
+ skipquiet = 'skipquiet' in args [1 :]
985
+ raw = 'raw' in args [1 :]
986
+
987
+ getclass = self .db .getclass
988
+ def get_prop_name (key , prop_name ):
989
+ # getclass and classname from enclosing method
990
+ klass = getclass (classname )
991
+ try :
992
+ property_obj = klass .properties [prop_name ]
993
+ except KeyError :
994
+ # the property has been removed from the schema.
995
+ return None
996
+ if isinstance (property_obj ,
997
+ (hyperdb .Link , hyperdb .Multilink )):
998
+ prop_class = getclass (property_obj .classname )
999
+ key_prop_name = prop_class .key
1000
+ if key_prop_name :
1001
+ return prop_class .get (key , key_prop_name )
1002
+ # None indicates that there is no key_prop
1003
+ return None
1004
+ return None
1005
+
1006
+ def get_prop_class (prop_name ):
1007
+ # getclass and classname from enclosing method
1008
+ klass = getclass (classname )
1009
+ try :
1010
+ property_obj = klass .properties [prop_name ]
1011
+ except KeyError :
1012
+ # the property has been removed from the schema.
1013
+ return None
1014
+ if isinstance (property_obj ,
1015
+ (hyperdb .Link , hyperdb .Multilink )):
1016
+ prop_class = getclass (property_obj .classname )
1017
+ return prop_class .classname
1018
+ return None # it's not a link
1019
+
1020
+ def _format_tuple_change (data , prop ):
1021
+ ''' ('-', ['2', '4'] ->
1022
+ "removed fred(2), jim(6)"
1023
+ '''
1024
+ if data [0 ] == '-' :
1025
+ op = _ ("removed" )
1026
+ elif data [0 ] == '+' :
1027
+ op = _ ("added" )
1028
+ else :
1029
+ raise ValueError (_ ("Unknown history set operation '%s'. "
1030
+ "Expected +/-." ) % op )
1031
+ op_params = data [1 ]
1032
+ name = get_prop_name (op_params [0 ], prop )
1033
+ if name is not None :
1034
+ list_items = ["%s(%s)" %
1035
+ (get_prop_name (o , prop ), o )
1036
+ for o in op_params ]
1037
+ else :
1038
+ propclass = get_prop_class (prop )
1039
+ if propclass : # noqa: SIM108
1040
+ list_items = ["%s%s" % (propclass , o )
1041
+ for o in op_params ]
1042
+ else :
1043
+ list_items = op_params
1044
+
1045
+ return "%s: %s" % (op , ", " .join (list_items ))
1046
+
1047
+ def format_report_class (_data ):
1048
+ """Eat the empty data dictionary or None"""
1049
+ return classname
1050
+
1051
+ def format_link (data ):
1052
+ '''data = ('issue', '157', 'dependson')'''
1053
+ # .Hint added issue23 to superseder
1054
+ f = _ ("added %(class)s%(item_id)s to %(propname)s" )
1055
+ return f % {
1056
+ 'class' : data [0 ], 'item_id' : data [1 ], 'propname' : data [2 ]}
1057
+
1058
+ def format_set (data ):
1059
+ '''data = set {'fyi': None, 'priority': '5'}
1060
+ set {'fyi': '....\n ed through cleanly', 'priority': '3'}
1061
+ '''
1062
+ result = []
1063
+
1064
+ # Note that set data is the old value. So don't use
1065
+ # current/future tense in sentences.
1066
+
1067
+ for prop , value in data .items ():
1068
+ if isinstance (value , str ):
1069
+ name = get_prop_name (value , prop )
1070
+ if name :
1071
+ result .append (
1072
+ # .Hint read as: assignedto was admin(1)
1073
+ # .Hint where assignedto is the property
1074
+ # .Hint admin is the key name for value 1
1075
+ _ ("%(prop)s was %(name)%(value)s)" ) % {
1076
+ "prop" : prop , "name" : name , "value" : value })
1077
+ else :
1078
+ # use repr so strings with embedded \n etc. don't
1079
+ # generate newlines in output. Try to keep each
1080
+ # journal entry on 1 line.
1081
+ result .append (_ ("%(prop)s was %(value)s" ) % {
1082
+ "prop" : prop , "value" : repr (value )})
1083
+ elif isinstance (value , list ):
1084
+ # test to see if there is a key prop.
1085
+ # Assumption, geting None here means no key
1086
+ # is defined for the property's class.
1087
+ name = get_prop_name (value [0 ], prop )
1088
+ if name is not None :
1089
+ list_items = ["%s(%s)" %
1090
+ (get_prop_name (v , prop ), v )
1091
+ for v in value ]
1092
+ else :
1093
+ prop_class = get_prop_class (prop )
1094
+ if prop_class : # noqa: SIM108
1095
+ list_items = [ "%s%s" % (prop_class , v )
1096
+ for v in value ]
1097
+ else :
1098
+ list_items = value
1099
+
1100
+ result .append (_ ("%(prop)s was [%(value_list)s]" ) % {
1101
+ "prop" : prop , "value_list" : ", " .join (list_items )})
1102
+ elif isinstance (value , tuple ):
1103
+ # operation data
1104
+ decorated = [_format_tuple_change (data , prop )
1105
+ for data in value ]
1106
+ result .append (# .Hint modified nosy: added demo(3)
1107
+ _ ("modified %(prop)s: %(how)s" ) % {
1108
+ "prop" : prop , "how" : ", " .join (decorated )})
1109
+ else :
1110
+ result .append (_ ("%(prop)s was %(value)s" ) % {
1111
+ "prop" : prop , "value" : value })
1112
+
1113
+ return '; ' .join (result )
1114
+
1115
+ def format_unlink (data ):
1116
+ '''data = ('issue', '157', 'dependson')'''
1117
+ return "removed %s%s from %s" % (data [0 ], data [1 ], data [2 ])
1118
+
1119
+ formatters = {
1120
+ "create" : format_report_class ,
1121
+ "link" : format_link ,
1122
+ "restored" : format_report_class ,
1123
+ "retired" : format_report_class ,
1124
+ "set" : format_set ,
1125
+ "unlink" : format_unlink ,
1126
+ }
980
1127
981
1128
try :
982
- print (self .db .getclass (classname ).history (nodeid ,
983
- skipquiet = skipquiet ))
1129
+ # returns a tuple: (
1130
+ # [0] = nodeid
1131
+ # [1] = date
1132
+ # [2] = userid
1133
+ # [3] = operation
1134
+ # [4] = details
1135
+ raw_history = self .db .getclass (classname ).history (nodeid ,
1136
+ skipquiet = skipquiet )
1137
+ if raw :
1138
+ print (raw_history )
1139
+ return 0
1140
+
1141
+ def make_readable (hist ):
1142
+ return "%s(%s) %s %s" % (self .db .user .get (hist [2 ], 'username' ),
1143
+ hist [1 ],
1144
+ hist [3 ],
1145
+ formatters .get (hist [3 ], lambda x : x )(
1146
+ hist [4 ]))
1147
+ printable_history = [make_readable (hist ) for hist in raw_history ]
1148
+
1149
+ print ("\n " .join (printable_history ))
984
1150
except KeyError :
985
1151
raise UsageError (_ ('no such class "%(classname)s"' ) % locals ())
986
1152
except IndexError :
@@ -2103,7 +2269,7 @@ def interactive(self):
2103
2269
".roundup_admin_history" )
2104
2270
2105
2271
try :
2106
- import readline # noqa: F401
2272
+ import readline
2107
2273
readline .read_init_file (initfile )
2108
2274
try :
2109
2275
readline .read_history_file (histfile )
@@ -2168,10 +2334,10 @@ def main(self): # noqa: PLR0912, PLR0911
2168
2334
self .print_designator = 0
2169
2335
self .verbose = 0
2170
2336
for opt , arg in opts :
2171
- if opt == '-h' : # noqa: RET505 - allow elif after returns
2337
+ if opt == '-h' :
2172
2338
self .usage ()
2173
2339
return 0
2174
- elif opt == '-v' :
2340
+ elif opt == '-v' : # noqa: RET505 - allow elif after returns
2175
2341
print ('%s (python %s)' % (roundup_version ,
2176
2342
sys .version .split ()[0 ]))
2177
2343
return 0
0 commit comments