tools/migration: Support for ~/ in paths
[prosody.git] / tools / migration / prosody-migrator.lua
1 #!/usr/bin/env lua
2
3 CFG_SOURCEDIR=os.getenv("PROSODY_SRCDIR");
4 CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR");
5
6 -- Substitute ~ with path to home directory in paths
7 if CFG_CONFIGDIR then
8         CFG_CONFIGDIR = CFG_CONFIGDIR:gsub("^~", os.getenv("HOME"));
9 end
10
11 if CFG_SOURCEDIR then
12         CFG_SOURCEDIR = CFG_SOURCEDIR:gsub("^~", os.getenv("HOME"));
13 end
14
15 local default_config = (CFG_CONFIGDIR or ".").."/migrator.cfg.lua";
16
17 -- Command-line parsing
18 local options = {};
19 local handled_opts = 0;
20 for i = 1, #arg do
21         if arg[i]:sub(1,2) == "--" then
22                 local opt, val = arg[i]:match("([%w-]+)=?(.*)");
23                 if opt then
24                         options[(opt:sub(3):gsub("%-", "_"))] = #val > 0 and val or true;
25                 end
26                 handled_opts = i;
27         else
28                 break;
29         end
30 end
31 table.remove(arg, handled_opts);
32
33 -- Load config file
34 local function loadfilein(file, env)
35         if loadin then
36                 return loadin(env, io.open(file):read("*a"));
37         else
38                 local chunk, err = loadfile(file);
39                 if chunk then
40                         setfenv(chunk, env);
41                 end
42                 return chunk, err;
43         end
44 end
45
46 local config_file = options.config or default_config;
47 local from_store = arg[1] or "input";
48 local to_store = arg[2] or "output";
49
50 config = {};
51 local config_env = setmetatable({}, { __index = function(t, k) return function(tbl) config[k] = tbl; end; end });
52 local config_chunk, err = loadfilein(config_file, config_env);
53 if not config_chunk then
54         print("There was an error loading the config file, check the file exists");
55         print("and that the syntax is correct:");
56         print("", err);
57         os.exit(1);
58 end
59
60 config_chunk();
61
62 if CFG_SOURCEDIR then
63         package.path = CFG_SOURCEDIR.."/?.lua;"..package.path;
64         package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath;
65 elseif not package.loaded["util.json"] then
66         package.path = "../../?.lua;"..package.path
67         package.cpath = "../../?.so;"..package.cpath
68 end
69
70 local have_err;
71 if #arg > 0 and #arg ~= 2 then
72         have_err = true;
73         print("Error: Incorrect number of parameters supplied.");
74 end
75 if not config[from_store] then
76         have_err = true;
77         print("Error: Input store '"..from_store.."' not found in the config file.");
78 end
79 if not config[to_store] then
80         have_err = true;
81         print("Error: Output store '"..to_store.."' not found in the config file.");
82 end
83
84 function load_store_handler(name)
85         local store_type = config[name].type;
86         if not store_type then
87                 print("Error: "..name.." store type not specified in the config file");
88                 return false;
89         else
90                 local ok, err = pcall(require, "migrator."..store_type);
91                 if not ok then
92                         if package.loaded["migrator."..store_type] then
93                                 print(("Error: Failed to initialize '%s' store:\n\t%s")
94                                         :format(name, err));
95                         else
96                                 print(("Error: Unrecognised store type for '%s': %s")
97                                         :format(from_store, store_type));
98                         end
99                         return false;
100                 end
101         end
102         return true;
103 end
104
105 have_err = have_err or not(load_store_handler(from_store, "input") and load_store_handler(to_store, "output"));
106
107 if have_err then
108         print("");
109         print("Usage: "..arg[0].." FROM_STORE TO_STORE");
110         print("If no stores are specified, 'input' and 'output' are used.");
111         print("");
112         print("The available stores in your migrator config are:");
113         print("");
114         for store in pairs(config) do
115                 print("", store);
116         end
117         print("");
118         os.exit(1);
119 end
120         
121 local itype = config[from_store].type;
122 local otype = config[to_store].type;
123 local reader = require("migrator."..itype).reader(config[from_store]);
124 local writer = require("migrator."..otype).writer(config[to_store]);
125
126 local json = require "util.json";
127
128 for x in reader do
129         --print(json.encode(x))
130         writer(x);
131 end
132 writer(nil); -- close
133