##// END OF EJS Templates
allow trimming to an empty database (--keep=0)
Paul Ivanov -
Show More
@@ -1,124 +1,126 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for managing IPython history.
3 An application for managing IPython history.
4
4
5 To be invoked as the `ipython history` subcommand.
5 To be invoked as the `ipython history` subcommand.
6 """
6 """
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 import os
9 import os
10 import sqlite3
10 import sqlite3
11
11
12 from IPython.config.application import Application
12 from IPython.config.application import Application
13 from IPython.core.application import BaseIPythonApplication
13 from IPython.core.application import BaseIPythonApplication
14 from IPython.utils.traitlets import Bool, Int, Dict
14 from IPython.utils.traitlets import Bool, Int, Dict
15
15
16 trim_hist_help = """Trim the IPython history database to the last 1000 entries.
16 trim_hist_help = """Trim the IPython history database to the last 1000 entries.
17
17
18 This actually copies the last 1000 entries to a new database, and then replaces
18 This actually copies the last 1000 entries to a new database, and then replaces
19 the old file with the new. Use the `--keep=` argument to specify a number
19 the old file with the new. Use the `--keep=` argument to specify a number
20 other than 1000.
20 other than 1000.
21 """
21 """
22
22
23 class HistoryTrim(BaseIPythonApplication):
23 class HistoryTrim(BaseIPythonApplication):
24 description = trim_hist_help
24 description = trim_hist_help
25
25
26 backup = Bool(False, config=True,
26 backup = Bool(False, config=True,
27 help="Keep the old history file as history.sqlite.<N>")
27 help="Keep the old history file as history.sqlite.<N>")
28
28
29 keep = Int(1000, config=True,
29 keep = Int(1000, config=True,
30 help="Number of recent lines to keep in the database.")
30 help="Number of recent lines to keep in the database.")
31
31
32 flags = Dict(dict(
32 flags = Dict(dict(
33 backup = ({'HistoryTrim' : {'backup' : True}},
33 backup = ({'HistoryTrim' : {'backup' : True}},
34 backup.get_metadata('help')
34 backup.get_metadata('help')
35 )
35 )
36 ))
36 ))
37
37
38 aliases=Dict(dict(
38 aliases=Dict(dict(
39 keep = 'HistoryTrim.keep'
39 keep = 'HistoryTrim.keep'
40 ))
40 ))
41
41
42 def start(self):
42 def start(self):
43 profile_dir = self.profile_dir.location
43 profile_dir = self.profile_dir.location
44 hist_file = os.path.join(profile_dir, 'history.sqlite')
44 hist_file = os.path.join(profile_dir, 'history.sqlite')
45 con = sqlite3.connect(hist_file)
45 con = sqlite3.connect(hist_file)
46
46
47 # Grab the recent history from the current database.
47 # Grab the recent history from the current database.
48 inputs = list(con.execute('SELECT session, line, source, source_raw FROM '
48 inputs = list(con.execute('SELECT session, line, source, source_raw FROM '
49 'history ORDER BY session DESC, line DESC LIMIT ?', (self.keep+1,)))
49 'history ORDER BY session DESC, line DESC LIMIT ?', (self.keep+1,)))
50 if len(inputs) <= self.keep:
50 if len(inputs) <= self.keep:
51 print("There are already at most %d entries in the history database." % self.keep)
51 print("There are already at most %d entries in the history database." % self.keep)
52 print("Not doing anything. Use --keep= argument to keep fewer entries")
52 print("Not doing anything. Use --keep= argument to keep fewer entries")
53 return
53 return
54
54
55 print("Trimming history to the most recent %d entries." % self.keep)
55 print("Trimming history to the most recent %d entries." % self.keep)
56
56
57 inputs.pop() # Remove the extra element we got to check the length.
57 inputs.pop() # Remove the extra element we got to check the length.
58 inputs.reverse()
58 inputs.reverse()
59 first_session = inputs[0][0]
59 if inputs:
60 outputs = list(con.execute('SELECT session, line, output FROM '
60 first_session = inputs[0][0]
61 'output_history WHERE session >= ?', (first_session,)))
61 outputs = list(con.execute('SELECT session, line, output FROM '
62 sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
62 'output_history WHERE session >= ?', (first_session,)))
63 'sessions WHERE session >= ?', (first_session,)))
63 sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
64 'sessions WHERE session >= ?', (first_session,)))
64 con.close()
65 con.close()
65
66
66 # Create the new history database.
67 # Create the new history database.
67 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new')
68 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new')
68 i = 0
69 i = 0
69 while os.path.exists(new_hist_file):
70 while os.path.exists(new_hist_file):
70 # Make sure we don't interfere with an existing file.
71 # Make sure we don't interfere with an existing file.
71 i += 1
72 i += 1
72 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new'+str(i))
73 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new'+str(i))
73 new_db = sqlite3.connect(new_hist_file)
74 new_db = sqlite3.connect(new_hist_file)
74 new_db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
75 new_db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
75 primary key autoincrement, start timestamp,
76 primary key autoincrement, start timestamp,
76 end timestamp, num_cmds integer, remark text)""")
77 end timestamp, num_cmds integer, remark text)""")
77 new_db.execute("""CREATE TABLE IF NOT EXISTS history
78 new_db.execute("""CREATE TABLE IF NOT EXISTS history
78 (session integer, line integer, source text, source_raw text,
79 (session integer, line integer, source text, source_raw text,
79 PRIMARY KEY (session, line))""")
80 PRIMARY KEY (session, line))""")
80 new_db.execute("""CREATE TABLE IF NOT EXISTS output_history
81 new_db.execute("""CREATE TABLE IF NOT EXISTS output_history
81 (session integer, line integer, output text,
82 (session integer, line integer, output text,
82 PRIMARY KEY (session, line))""")
83 PRIMARY KEY (session, line))""")
83 new_db.commit()
84 new_db.commit()
84
85
85
86
86 with new_db:
87 if inputs:
87 # Add the recent history into the new database.
88 with new_db:
88 new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
89 # Add the recent history into the new database.
89 new_db.executemany('insert into history values (?,?,?,?)', inputs)
90 new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
90 new_db.executemany('insert into output_history values (?,?,?)', outputs)
91 new_db.executemany('insert into history values (?,?,?,?)', inputs)
92 new_db.executemany('insert into output_history values (?,?,?)', outputs)
91 new_db.close()
93 new_db.close()
92
94
93 if self.backup:
95 if self.backup:
94 i = 1
96 i = 1
95 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
97 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
96 while os.path.exists(backup_hist_file):
98 while os.path.exists(backup_hist_file):
97 i += 1
99 i += 1
98 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
100 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
99 os.rename(hist_file, backup_hist_file)
101 os.rename(hist_file, backup_hist_file)
100 print("Backed up longer history file to", backup_hist_file)
102 print("Backed up longer history file to", backup_hist_file)
101 else:
103 else:
102 os.remove(hist_file)
104 os.remove(hist_file)
103
105
104 os.rename(new_hist_file, hist_file)
106 os.rename(new_hist_file, hist_file)
105
107
106
108
107 class HistoryApp(Application):
109 class HistoryApp(Application):
108 name = u'ipython-history'
110 name = u'ipython-history'
109 description = "Manage the IPython history database."
111 description = "Manage the IPython history database."
110
112
111 subcommands = Dict(dict(
113 subcommands = Dict(dict(
112 trim = (HistoryTrim, HistoryTrim.description.splitlines()[0]),
114 trim = (HistoryTrim, HistoryTrim.description.splitlines()[0]),
113 ))
115 ))
114
116
115 def start(self):
117 def start(self):
116 if self.subapp is None:
118 if self.subapp is None:
117 print("No subcommand specified. Must specify one of: %s" % \
119 print("No subcommand specified. Must specify one of: %s" % \
118 (self.subcommands.keys()))
120 (self.subcommands.keys()))
119 print()
121 print()
120 self.print_description()
122 self.print_description()
121 self.print_subcommands()
123 self.print_subcommands()
122 self.exit(1)
124 self.exit(1)
123 else:
125 else:
124 return self.subapp.start()
126 return self.subapp.start()
General Comments 0
You need to be logged in to leave comments. Login now