2 from optparse
import OptionParser
9 import pokedex
.db
.tables
13 if len(sys
.argv
) <= 1:
19 # XXX there must be a better way to get Unicode argv
20 # XXX this doesn't work on Windows durp
21 enc
= sys
.stdin
.encoding
or 'utf8'
22 args
= [_
.decode(enc
) for _
in args
]
24 # Find the command as a function in this file
25 func
= globals().get("command_%s" % command
, None)
32 def get_parser(verbose
=True):
33 """Returns an OptionParser prepopulated with the global options.
35 `verbose` is whether or not the options should be verbose by default.
37 parser
= OptionParser()
38 parser
.add_option('-e', '--engine', dest
='engine_uri', default
=os
.environ
.get('POKEDEX_DB_ENGINE', None))
39 parser
.add_option('-i', '--index', dest
='index_dir', default
=os
.environ
.get('POKEDEX_INDEX_DIR', None))
40 parser
.add_option('-q', '--quiet', dest
='verbose', default
=verbose
, action
='store_false')
41 parser
.add_option('-v', '--verbose', dest
='verbose', default
=verbose
, action
='store_true')
44 def get_session(options
):
45 """Given a parsed options object, connects to the database and returns a
49 # WARNING: This logic duplicates that in db.connect(), because there's no
50 # other reliable way to tell where the engine actually came from. Keep it
52 engine_uri
= options
.engine_uri
55 got_from
= 'command line'
57 engine_uri
= os
.environ
.get('POKEDEX_DB_ENGINE', None)
59 got_from
= 'environment'
61 got_from
= 'default setting'
63 session
= pokedex
.db
.connect(engine_uri
)
66 print "Connected to database {engine} (from {got_from})" \
67 .format(engine
=session
.bind
.url
, got_from
=got_from
)
71 def get_lookup(options
, session
=None, recreate
=False):
72 """Given a parsed options object, opens the whoosh index and returns a
76 # WARNING: This logic duplicates that in PokedexLookup, because there's no
77 # other reliable way to tell where the engine actually came from. Keep it
79 if recreate
and not session
:
80 raise ValueError("get_lookup() needs an explicit session to regen the index")
82 index_dir
= options
.index_dir
85 got_from
= 'command line'
87 index_dir
= os
.environ
.get('POKEDEX_INDEX_DIR', None)
89 got_from
= 'environment'
91 index_dir
= pkg_resources
.resource_filename('pokedex',
93 got_from
= 'default setting'
96 print "Opened lookup index {index_dir} (from {got_from})" \
97 .format(index_dir
=index_dir
, got_from
=got_from
)
99 lookup
= pokedex
.lookup
.PokedexLookup(index_dir
, session
=session
)
102 lookup
.rebuild_index()
106 def get_csv_directory(options
):
107 """Prints and returns the csv directory we're about to use."""
109 if not options
.verbose
:
112 if options
.directory
:
113 csvdir
= options
.directory
114 got_from
= 'command line'
116 # This is the same as the db.load default
117 csvdir
= pkg_resources
.resource_filename('pokedex', 'data/csv')
118 got_from
= 'default setting'
120 print "Using CSV directory {csvdir} (from {got_from})" \
121 .format(csvdir
=csvdir
, got_from
=got_from
)
126 ### Plumbing commands
128 def command_dump(*args
):
129 parser
= get_parser(verbose
=True)
130 parser
.add_option('-d', '--directory', dest
='directory', default
=None)
131 options
, tables
= parser
.parse_args(list(args
))
133 session
= get_session(options
)
134 get_csv_directory(options
)
136 pokedex
.db
.load
.dump(session
, directory
=options
.directory
,
138 verbose
=options
.verbose
)
140 def command_load(*args
):
141 parser
= get_parser(verbose
=True)
142 parser
.add_option('-d', '--directory', dest
='directory', default
=None)
143 parser
.add_option('-D', '--drop-tables', dest
='drop_tables', default
=False, action
='store_true')
144 options
, tables
= parser
.parse_args(list(args
))
146 if not options
.engine_uri
:
147 print "WARNING: You're reloading the default database, but not the lookup index. They"
148 print " might get out of sync, and pokedex commands may not work correctly!"
149 print "To fix this, run `pokedex reindex` when this command finishes. Or, just use"
150 print "`pokedex setup` to do both at once."
153 session
= get_session(options
)
154 get_csv_directory(options
)
156 pokedex
.db
.load
.load(session
, directory
=options
.directory
,
157 drop_tables
=options
.drop_tables
,
159 verbose
=options
.verbose
)
161 def command_reindex(*args
):
162 parser
= get_parser(verbose
=True)
163 options
, _
= parser
.parse_args(list(args
))
165 session
= get_session(options
)
166 lookup
= get_lookup(options
, session
=session
, recreate
=True)
168 print "Recreated lookup index."
171 def command_setup(*args
):
172 parser
= get_parser(verbose
=False)
173 options
, _
= parser
.parse_args(list(args
))
175 options
.directory
= None
177 session
= get_session(options
)
178 get_csv_directory(options
)
179 pokedex
.db
.load
.load(session
, directory
=None, drop_tables
=True,
180 verbose
=options
.verbose
)
182 lookup
= get_lookup(options
, session
=session
, recreate
=True)
184 print "Recreated lookup index."
187 def command_status(*args
):
188 parser
= get_parser(verbose
=True)
189 options
, _
= parser
.parse_args(list(args
))
190 options
.verbose
= True
191 options
.directory
= None
193 # Database, and a lame check for whether it's been inited at least once
194 session
= get_session(options
)
195 print " - OK! Connected successfully."
197 if pokedex
.db
.tables
.Pokemon
.__table__
.exists(session
.bind
):
198 print " - OK! Database seems to contain some data."
200 print " - WARNING: Database appears to be empty."
202 # CSV; simple checks that the dir exists
203 csvdir
= get_csv_directory(options
)
204 if not os
.path
.exists(csvdir
):
205 print " - ERROR: No such directory!"
206 elif not os
.path
.isdir(csvdir
):
207 print " - ERROR: Not a directory!"
209 print " - OK! Directory exists."
211 if os
.access(csvdir
, os
.R_OK
):
212 print " - OK! Can read from directory."
214 print " - ERROR: Can't read from directory!"
216 if os
.access(csvdir
, os
.W_OK
):
217 print " - OK! Can write to directory."
219 print " - WARNING: Can't write to directory! " \
220 "`dump` will not work. You may need to sudo."
222 # Index; the PokedexLookup constructor covers most tests and will
223 # cheerfully bomb if they fail
224 lookup
= get_lookup(options
, recreate
=False)
225 print " - OK! Opened successfully."
228 ### User-facing commands
230 def command_lookup(*args
):
231 parser
= get_parser(verbose
=False)
232 options
, words
= parser
.parse_args(list(args
))
234 name
= u
' '.join(words
)
236 session
= get_session(options
)
237 lookup
= get_lookup(options
, session
=session
, recreate
=False)
239 results
= lookup
.lookup(name
)
242 elif results
[0].exact
:
245 print "Fuzzy-matched:"
247 for result
in results
:
248 if hasattr(result
.object, 'full_name'):
249 name
= result
.object.full_name
251 name
= result
.object.name
253 print "%s: %s" %
(result
.object.__tablename__
, name
),
255 print "(%s in %s)" %
(result
.name
, result
.language
)
261 print u
"""pokedex -- a command-line Pokédex interface
262 usage: pokedex {command} [options...]
263 Run `pokedex setup` first, or nothing will work!
264 See http://bugs.veekun.com/projects/pokedex/wiki/CLI for more documentation.
267 help Displays this message.
268 lookup [thing] Look up something in the Pokédex.
271 load Load Pokédex data into a database from CSV files.
272 dump Dump Pokédex data from a database into CSV files.
273 reindex Rebuilds the lookup index from the database.
274 setup Combines load and reindex.
275 status No effect, but prints which engine, index, and csv
276 directory would be used for other commands.
279 -e|--engine=URI By default, all commands try to use a SQLite database
280 in the pokedex install directory. Use this option (or
281 a POKEDEX_DB_ENGINE environment variable) to specify an
283 -i|--index=DIR By default, all commands try to put the lookup index in
284 the pokedex install directory. Use this option (or a
285 POKEDEX_INDEX_DIR environment variable) to specify an
287 -q|--quiet Don't print system output. This is the default for
288 non-system commands and setup.
289 -v|--verbose Print system output. This is the default for system
290 commands, except setup.
293 -d|--directory=DIR By default, load and dump will use the CSV files in the
294 pokedex install directory. Use this option to specify
295 a different directory.
296 -D|--drop-tables With load, drop all tables before loading data.
298 Additionally, load and dump accept a list of table names (possibly with
299 wildcards) and/or csv fileames as an argument list.
300 """.encode(sys
.getdefaultencoding(), 'replace')