Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

# -*- coding: UTF-8 -*- 

# Copyright 2012 Luc Saffre 

# License: BSD (see file COPYING for details) 

 

""" 

Writes a status report about this Site.  

Used to monitor a production database.  

""" 

from future import standard_library 

standard_library.install_aliases() 

 

import logging 

logger = logging.getLogger(__name__) 

 

import os 

import errno 

import pickle as pickle 

import sys 

from optparse import make_option 

from os.path import join 

 

from django.db import models 

from django.conf import settings 

from django.utils import timezone 

from django.utils.translation import ugettext as _ 

from django.utils.encoding import force_text 

from django.core.management import call_command 

from django.core.management.base import BaseCommand, CommandError 

 

from django.db import connections, transaction 

from django.core.exceptions import ImproperlyConfigured 

from django.db.utils import DEFAULT_DB_ALIAS 

 

from django.db.backends.sqlite3.base import DatabaseWrapper as sqlite 

try: 

    from django.db.backends.mysql.base import DatabaseWrapper as mysql 

except ImproperlyConfigured: 

    mysql = None 

 

 

import lino 

from lino.utils import rstgen 

from lino.core.utils import obj2str, full_model_name, sorted_models_list 

 

 

def diffs(old, new, prefix=''): 

    if type(old) != dict: 

        if old != new: 

            yield "%s : %s -> %s" % (prefix, old, new) 

        return 

    keys = set(list(old.keys()) + list(new.keys())) 

    keys.discard('timestamp') 

    #~ diffs = [] 

    if prefix: 

        prefix += ' ' 

    for k in keys: 

        ov = old.get(k) 

        nv = new.get(k) 

        if ov != nv: 

            for d in diffs(ov, nv, prefix + k): 

                yield d 

                #~ yield "%s : %s -> %s"  % (k, ov, nv) 

 

 

def compare(old, new): 

    changes = list(diffs(old, new)) 

    if len(changes): 

        msg = "Changes since %s:" % old.get('timestamp') 

        msg += '\n- ' + ('\n- '.join(changes)) 

        #~ logger.info(msg) 

        #~ logger.info('- ' + ('- '.join(changes))) 

        return msg 

    else: 

        logger.debug("No changes since %s", old.get('timestamp')) 

 

 

class Command(BaseCommand): 

    help = __doc__ 

 

    option_list = BaseCommand.option_list + ( 

        make_option('--nowrite', action='store_false', 

                    dest='write', default=True, 

                    help='Do not write status to pickle.'), 

    ) 

 

    def handle(self, *args, **options): 

        if args: 

            raise CommandError("This command doesn't accept any arguments.") 

 

        self.options = options 

 

        #~ settings.SITE.startup() 

 

        state = dict() 

        state.update(timestamp=timezone.now()) 

        state.update(lino_version=lino.__version__) 

 

        states_file = os.path.join(settings.SITE.project_dir, 'states.pck') 

 

        if os.path.exists(states_file): 

            fd = open(states_file) 

            states_list = pickle.load(fd) 

            fd.close() 

            logger.info("Loaded %d states from %s", 

                        len(states_list), states_file) 

        else: 

            states_list = [] 

 

        models_list = sorted_models_list() 

 

        apps = [p.app_label for p in settings.SITE.installed_plugins] 

        state.update(applications=" ".join(apps)) 

        for model in models_list: 

            if model._meta.managed: 

                model_state = dict() 

                #~ cells.append(str(i)) 

                #~ cells.append(full_model_name(model)) 

                #~ cells.append(str(model)) 

                #~ if model._meta.managed: 

                    #~ cells.append('X') 

                #~ else: 

                    #~ cells.append('') 

                model_state.update(fields=[f.name for f in model._meta.fields]) 

                #~ qs = model.objects.all() 

                qs = model.objects.order_by('pk') 

                n = qs.count() 

                model_state.update(rows=n) 

 

                connection = connections[DEFAULT_DB_ALIAS] 

 

                #~ if isinstance(connection,sqlite): 

                    #~ cells.append("-") 

                if mysql and isinstance(connection, mysql): 

 

                    cursor = connection.cursor() 

                    dbname = connection.settings_dict['NAME'] 

                    sql = """\ 

                    SELECT (data_length+index_length) tablesize 

                    FROM information_schema.tables 

                    WHERE table_schema='%s' and table_name='%s'; 

                    """ % (dbname, model._meta.db_table) 

                    #~ print sql 

                    cursor.execute(sql) 

                    row = cursor.fetchone() 

                    if row is not None: 

                        model_state.update(bytes=row[0]) 

                else: 

                    pass 

 

                state[full_model_name(model)] = model_state 

 

        if len(states_list): 

            msg = compare(state, states_list[-1]) 

            if msg: 

                logger.info(msg) 

                #~ sendmail_admins() 

 

        states_list.append(state) 

 

        #~ print state 

        if self.options['write']: 

            f = open(states_file, 'w') 

            pickle.dump(states_list, f) 

            logger.info("Saved %d states to %s", len(states_list), states_file)