oops; put this into the migration_tools schema
[migration-tools.git] / mig
1 #!/usr/bin/perl -w
2 ###############################################################################
3 =pod
4
5 =head1 NAME
6
7 mig - git-like program for tracking and manipulating legacy data files for
8 migrations
9
10 =head1 SYNOPSIS
11
12 B<mig> <command> [argument] [...]
13
14 =head1 DESCRIPTION
15
16 B<mig> is used to track and manipulate CSV or CSV-like text files exported from
17 legacy systems for migration into Evergreen.  It can be a wrapper for some
18 other migration tools and tracks state using a PostgreSQL table in a given
19 migration schema.
20
21 It makes use of certain environment variables that may be set by the B<mig-env>
22 tool: PGHOST, PGPORT, PGUSER, PGDATABASE, MIGSCHEMA, and MIGWORKDIR
23
24 For most commands, if the current working directory falls outside of the
25 directory specified by MIGWORKDIR, then mig will assume that environment is
26 also incorrect and bail before doing any actual work.
27
28 ~/.pgpass should also be configured, as B<mig> will not prompt for a database
29 password.
30
31 Only the B<env> and B<help> commands work without the MIGSCHEMA environment
32 variable being set.
33
34 =head1 OVERVIEW
35
36 Using B<mig> should go something like this:
37
38 =over 15
39
40 =item mig env create m_foo # Sets up the environment
41
42 =item mig env use m_foo # Spawns a shell using the configured environment
43
44 =item mig init # creates the m_foo schema in the database if needed, and other tables
45
46 =item mig add patrons.tsv # tracks an incoming data file; repeat for additional files
47
48 =item mig iconv patrons.tsv # convert it to UTF8, creating patrons.tsv.utf8
49
50 =item mig clean patrons.tsv # cleans the file, creating patrons.tsv.utf8.clean
51
52 =item mig link patrons.tsv actor_usr # makes the soon-to-be staging table a child of m_foo.actor_usr
53
54 =item mig convert patrons.tsv # creates a .sql file for staging the data
55
56 =item mig stage patrons.tsv # load said .sql file
57
58 =item mig mapper patrons.tsv # interactive tool for analyzing/mapping the staging table
59
60 =item mig analysis patrons.tsv # writes a summary .tsv file of mapped/flagged fields from the staging table
61
62 =item mig map patrons.tsv # apply configured mappings
63
64 =item mig write_prod patrons.tsv # creates a .sql file for pushing the staging data into production
65
66 =item mig reporter --analyst "Foo Fooer" --report_title "Foo Load Analysis" #creates an asciidoc report
67
68 =item mig gsheet --pull foo_tab_name OR --push foo_pg_table_name 
69
70 =item mig stagebibs --file foo.xml 
71
72 =back
73
74 =head1 COMMANDS
75
76 =over 15
77
78 =item B<help> [command]
79
80 Display this very same documentation, or specific documentation for one of the
81 commands listed here.
82
83 =item B<env> <create|use|show> <schema>
84
85 Invokes B<mig-env> with the same arguments.  I<mig-env> can set important
86 environment variables and spawn a shell with those variables, and it also does
87 some directory creation and symlinking.
88
89 =item B<init>
90
91 Create or re-create the PostgreSQL tracking table for the schema specified by
92 the MIGSCHEMA environment variable.  If needed, create the migration schema
93 itself and run migration_tools.init() and build() if the migration_tools schema
94 exists.
95
96 =item B<status> [file] [...]
97
98 Show status information for either the specified files or all tracked files if
99 no argument is given.
100
101 =item B<add> [--no-headers|--headers] <file> [file|--no-headers|--headers] [...]
102
103 Add the specified files to the migration tracker.  Until --no-headers is
104 specified, the tracker will assume the files have headers.
105
106 You can do crazy stuff like
107 B<mig add file1 --no-headers file2 file3 --headers file4>
108
109 =item B<remove> <file> [file] [...]
110
111 Remove the specified files from the migration tracker.
112
113 =item B<iconv> <file> [other arguments...]
114
115 Attempts to invoke B<iconv> on the specified tracked file, placing the output in
116 <file>.utf8
117
118 If given no other arguments, the invocation will lool like
119
120 =over 5
121
122 iconv -f ISO-8859-1 -t UTF-8 -o <file>.utf8 <file>
123
124 =back
125
126 otherwise, the arguments will be passed through like so
127
128 =over 5
129
130 iconv [other arguments...] -o <file>.utf8 <file>
131
132 =back
133
134 =item B<skip-iconv> <file>
135
136 If this is used instead of B<iconv>, then B<mig> will look for an existing
137 <file>.utf8 and use it instead of attempting to create one.
138
139 =item B<clean> <file> [other arguments...]
140
141 Attempts to invoke B<clean_csv> on the iconv-converted specified tracked file,
142 placing the output in <file>.utf8.clean
143
144 If given no other arguments, the invocation will lool like
145
146 =over 5
147
148 clean_csv --config scripts/clean.conf --fix --apply <--create-headers> <file>
149
150 =back
151
152 otherwise, the arguments will be passed through like so
153
154 =over 5
155
156 clean_csv [other arguments...] <file>
157
158 =back
159
160 =item B<skip-clean> <file>
161
162 If this is used instead of B<clean>, then B<mig> will look for an existing
163 <file>.utf8.clean and use it instead of attempting to create one.
164
165 =item B<link> <file> <parent table>
166
167 Associate the specified file with a parent table within the migration schema.
168
169 Linking multiple files to the same parent table is not allowed currently.
170
171 =item B<unlink> <file>
172
173 Removes any association between the specified file and a parent table within
174 the migration schema.
175
176 =item B<convert> <file>
177
178 Attempts to invoke B<csv2sql> on the .utf8.clean version of the specified
179 tracked file, creating either [file].utf8.clean.stage.sql or
180 <parent table>_stage.sql depending on whether the file has been linked to a
181 parent table within the migration schema or not.
182
183 If given no other arguments, the invocation will lool like
184
185 =over 5
186
187 csv2sql --config scripts/clean.conf --add-x-migrate --schema <MIGSCHEMA> [--parent <PARENT TABLE>] -o <[<file>.utf8.clean.stage.sql]|[parent_table_stage.sql]> <FILE>.utf8.clean
188
189 =back
190
191 otherwise, the arguments will be passed through like so
192
193 =over 5
194
195 csv2sql [other arguments...] -o <[<file>.utf8.clean.stage.sql]|[parent_table_stage.sql]> <file>.utf8.clean
196
197 =back
198
199 =item B<stage> <file> [other arguments...]
200
201 Load the SQL-converted version of the specified file into the migration schema.
202
203 Extra arguments are passed to the underlying call to psql
204
205 =item B<mapper> <file>
206
207 Interactive session for analyzing, flagging, and mapping legacy field data to
208 Evergreen fields.
209
210 Upon exit, generate either [file].clean.map.sql or <parent table>_map.sql. The
211 SQL generated will be UPDATE's for setting the Evergreen-specific columns for a
212 given file's staging tables, and TRUNCATE's and INSERT's for auxilary tables.
213 The files will have \include hooks for pulling in additional mapping files
214 (for example, end-user mappings for circ modifiers, etc.)
215
216 =item B<analysis> [file]
217
218 Writes a MIGSCHEMA.tsv file containing a break-down of mapped and flagged
219 fields from the specified file, or all staged files if no file is specified.
220
221 The main goal of the tsv file is to present end-user mappable data for circ
222 modifiers, shelving locations, patron profiles, etc.  We use spreadsheets for
223 this now but may move to a dedicated UI in the future.
224
225 =item B<map> [file]
226
227 Applies the mapping sql to the migration schema for the specified mapped file,
228 or for all mapped files if no file is specified.
229
230 =item B<write_prod> [file]
231
232 Generates <parent table>_prod.sql for the specified linked and mapped file, or
233 all such files if no file is specified.
234
235 =item B<sql> [arguments...]
236
237 A wrapper around the psql command.  At some point the plan is to shove mig-tracked variables into psql sessions.
238
239 =item B<reporter> --analyst "Analyst Name" --report_title "Report Title"
240
241 Generates an asciidoc file in the git working directory that can be converted to 
242 any appropriate format.  The analyst and report parameters are required.
243
244 Optional parameters are : 
245
246 --added_page_title and --added_page_file 
247
248 If one is used both must be.  The added page file can be plain text or asciidoc.  This
249 adds an extra arbitrary page of notes to the report.  Mig assumes the page file is in the mig git directory.
250
251 --tags
252
253 This will define a set of tags to use, if not set it will default to Circs, 
254 Holds, Actors, Bibs, Assets & Money. 
255
256 --debug
257
258 Gives more information about what is happening.
259
260 --reports_xml 
261
262 Allows you to override the default evergreen_staged_report.xml in the mig-xml folder.
263
264 =item B<gsheet> --pull or --push spreadsheet_tab
265
266 This uses the gsheet_tracked_table and gsheet_tracked column tables to map a Google Docs Spreadsheet tabs
267 with Postgres tables in the mig schema.  The spreadsheet is assumed to share the name as the mig schema. 
268 Tab names must be unique.  Each spreadsheet column needs a header that matches the column name in the matching 
269 table.  An oauth session key is also needed for your Google account and mig gsheet will look for it in the 
270 .mig directory.
271
272 =back
273
274 =cut
275
276 ###############################################################################
277
278 use strict;
279 use Switch;
280 use Env qw(
281     HOME PGHOST PGPORT PGUSER PGDATABASE MIGSCHEMA
282     MIGBASEWORKDIR MIGBASEGITDIR MIGGITDIR MIGWORKDIR
283 );
284 use Pod::Usage;
285 use FindBin;
286 my $mig_bin = "$FindBin::Bin/mig-bin/";
287 use lib "$FindBin::Bin/mig-bin";
288 use Mig;
289
290 pod2usage(-verbose => 2) if ! $ARGV[0];
291 switch($ARGV[0]) {
292     case "help" {
293         if (defined $ARGV[1]) {
294             my $cmd = $mig_bin . "mig-$ARGV[1]";
295             if (-e $cmd) {
296                 system( $mig_bin . "mig-$ARGV[1]", '--help' );
297             } else {
298                 pod2usage(-verbose => 2);
299             }
300         } else {
301             pod2usage(-verbose => 2);
302         }
303     }
304     case "map" {
305     }
306     case "load" {
307     }
308     case "wdir" {
309         print "$MIGWORKDIR\n";
310     }
311     case "gdir" {
312         print "$MIGBASEGITDIR\n";
313     }
314     case "sdir" {
315         print "$MIGGITDIR\n";
316     }
317     else {
318         standard_invocation(@ARGV);
319     }
320 }
321
322 sub standard_invocation {
323     my $cmd = shift;
324
325     if ($cmd ne 'env') { Mig::die_if_no_env_migschema(); }
326     if (-e $mig_bin . "mig-$cmd") {
327         system( $mig_bin . "mig-$cmd", @_ );
328     } else {
329         system( "mig-$cmd", @_ ) == 0 or die pod2usage(1);
330     }
331
332 }
333
334