Paul Martin
2016-04-16 eecaad8b8e2c447429c31a01d49260ddd6b4ee03
commit | author | age
4d81c9 1 /*
JM 2  * Copyright 2014 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit;
17
18 import java.io.File;
19 import java.text.MessageFormat;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Set;
23 import java.util.concurrent.TimeUnit;
24
25 import org.kohsuke.args4j.Argument;
26 import org.kohsuke.args4j.CmdLineException;
27 import org.kohsuke.args4j.CmdLineParser;
28 import org.kohsuke.args4j.Option;
29
30 import com.gitblit.manager.IRepositoryManager;
31 import com.gitblit.manager.IRuntimeManager;
32 import com.gitblit.manager.RepositoryManager;
33 import com.gitblit.manager.RuntimeManager;
34 import com.gitblit.models.RepositoryModel;
35 import com.gitblit.models.TicketModel;
36 import com.gitblit.models.TicketModel.Change;
37 import com.gitblit.tickets.BranchTicketService;
38 import com.gitblit.tickets.FileTicketService;
39 import com.gitblit.tickets.ITicketService;
40 import com.gitblit.tickets.RedisTicketService;
41 import com.gitblit.utils.StringUtils;
fc3a39 42 import com.gitblit.utils.XssFilter;
JM 43 import com.gitblit.utils.XssFilter.AllowXssFilter;
4d81c9 44
JM 45 /**
46  * A command-line tool to move all tickets from one ticket service to another.
47  *
48  * @author James Moger
49  *
50  */
51 public class MigrateTickets {
52
53     public static void main(String... args) {
54         MigrateTickets migrate = new MigrateTickets();
55
56         // filter out the baseFolder parameter
57         List<String> filtered = new ArrayList<String>();
58         String folder = "data";
59         for (int i = 0; i < args.length; i++) {
60             String arg = args[i];
61             if (arg.equals("--baseFolder")) {
62                 if (i + 1 == args.length) {
63                     System.out.println("Invalid --baseFolder parameter!");
64                     System.exit(-1);
65                 } else if (!".".equals(args[i + 1])) {
66                     folder = args[i + 1];
67                 }
68                 i = i + 1;
69             } else {
70                 filtered.add(arg);
71             }
72         }
73
74         Params.baseFolder = folder;
75         Params params = new Params();
76         CmdLineParser parser = new CmdLineParser(params);
77         try {
78             parser.parseArgument(filtered);
79             if (params.help) {
80                 migrate.usage(parser, null);
81                 return;
82             }
83         } catch (CmdLineException t) {
84             migrate.usage(parser, t);
85             return;
86         }
87
88         // load the settings
89         FileSettings settings = params.FILESETTINGS;
90         if (!StringUtils.isEmpty(params.settingsfile)) {
91             if (new File(params.settingsfile).exists()) {
92                 settings = new FileSettings(params.settingsfile);
93             }
94         }
95
96         // migrate tickets
97         migrate.migrate(new File(Params.baseFolder), settings, params.outputServiceName);
98         System.exit(0);
99     }
100
101     /**
102      * Display the command line usage of MigrateTickets.
103      *
104      * @param parser
105      * @param t
106      */
107     protected final void usage(CmdLineParser parser, CmdLineException t) {
108         System.out.println(Constants.BORDER);
109         System.out.println(Constants.getGitBlitVersion());
110         System.out.println(Constants.BORDER);
111         System.out.println();
112         if (t != null) {
113             System.out.println(t.getMessage());
114             System.out.println();
115         }
116         if (parser != null) {
117             parser.printUsage(System.out);
118             System.out
119                     .println("\nExample:\n  java -gitblit.jar com.gitblit.MigrateTickets com.gitblit.tickets.RedisTicketService --baseFolder c:\\gitblit-data");
120         }
121         System.exit(0);
122     }
123
124     /**
125      * Migrate all tickets
126      *
127      * @param baseFolder
128      * @param settings
129      * @param outputServiceName
130      */
131     protected void migrate(File baseFolder, IStoredSettings settings, String outputServiceName) {
132         // disable some services
133         settings.overrideSetting(Keys.web.allowLuceneIndexing, false);
134         settings.overrideSetting(Keys.git.enableGarbageCollection, false);
135         settings.overrideSetting(Keys.git.enableMirroring, false);
136         settings.overrideSetting(Keys.web.activityCacheDays, 0);
137         settings.overrideSetting(ITicketService.SETTING_UPDATE_DIFFSTATS, false);
138
fc3a39 139         XssFilter xssFilter = new AllowXssFilter();
JM 140         IRuntimeManager runtimeManager = new RuntimeManager(settings, xssFilter, baseFolder).start();
eecaad 141         IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, null, null, null).start();
4d81c9 142
JM 143         String inputServiceName = settings.getString(Keys.tickets.service, BranchTicketService.class.getSimpleName());
144         if (StringUtils.isEmpty(inputServiceName)) {
145             System.err.println(MessageFormat.format("Please define a ticket service in \"{0}\"", Keys.tickets.service));
146             System.exit(1);
147         }
148
149         ITicketService inputService = null;
150         ITicketService outputService = null;
151         try {
152             inputService = getService(inputServiceName, runtimeManager, repositoryManager);
153             outputService = getService(outputServiceName, runtimeManager, repositoryManager);
154         } catch (Exception e) {
155             e.printStackTrace();
156             System.exit(1);
157         }
158
159         if (!inputService.isReady()) {
160             System.err.println(String.format("%s INPUT service is not ready, check config.", inputService.getClass().getSimpleName()));
161             System.exit(1);
162         }
163
164         if (!outputService.isReady()) {
165             System.err.println(String.format("%s OUTPUT service is not ready, check config.", outputService.getClass().getSimpleName()));
166             System.exit(1);
167         }
168
169         // migrate tickets
170         long start = System.nanoTime();
171         long totalTickets = 0;
172         long totalChanges = 0;
e58e09 173         for (RepositoryModel repository : repositoryManager.getRepositoryModels()) {
4d81c9 174             Set<Long> ids = inputService.getIds(repository);
JM 175             if (ids == null || ids.isEmpty()) {
176                 // nothing to migrate
177                 continue;
178             }
179
180             // delete any tickets we may have in the output ticket service
181             outputService.deleteAll(repository);
182
183             for (long id : ids) {
184                 List<Change> journal = inputService.getJournal(repository, id);
185                 if (journal == null || journal.size() == 0) {
186                     continue;
187                 }
188                 TicketModel ticket = outputService.createTicket(repository, id, journal.get(0));
189                 if (ticket == null) {
190                     System.err.println(String.format("Failed to migrate %s #%s", repository.name, id));
191                     System.exit(1);
192                 }
193                 totalTickets++;
194                 System.out.println(String.format("%s #%s: %s", repository.name, ticket.number, ticket.title));
195                 for (int i = 1; i < journal.size(); i++) {
196                     TicketModel updated = outputService.updateTicket(repository, ticket.number, journal.get(i));
197                     if (updated != null) {
198                         System.out.println(String.format("   applied change %d", i));
199                         totalChanges++;
200                     } else {
201                         System.err.println(String.format("Failed to apply change %d:\n%s", i, journal.get(i)));
202                         System.exit(1);
203                     }
204                 }
205             }
206         }
207
208         inputService.stop();
209         outputService.stop();
210
211         repositoryManager.stop();
212         runtimeManager.stop();
213
214         long end = System.nanoTime();
215
216         System.out.println(String.format("Migrated %d tickets composed of %d journal entries in %d seconds",
217                 totalTickets, totalTickets + totalChanges, TimeUnit.NANOSECONDS.toSeconds(end - start)));
218     }
219
220     protected ITicketService getService(String serviceName, IRuntimeManager runtimeManager, IRepositoryManager repositoryManager) throws Exception {
221         ITicketService service = null;
222         Class<?> serviceClass = Class.forName(serviceName);
223         if (RedisTicketService.class.isAssignableFrom(serviceClass)) {
224             // Redis ticket service
225             service = new RedisTicketService(runtimeManager, null, null, null, repositoryManager).start();
226         } else if (BranchTicketService.class.isAssignableFrom(serviceClass)) {
227             // Branch ticket service
228             service = new BranchTicketService(runtimeManager, null, null, null, repositoryManager).start();
229         } else if (FileTicketService.class.isAssignableFrom(serviceClass)) {
230             // File ticket service
231             service = new FileTicketService(runtimeManager, null, null, null, repositoryManager).start();
232         } else {
233             System.err.println("Unknown ticket service " + serviceName);
234         }
235         return service;
236     }
237
238     /**
239      * Parameters.
240      */
241     public static class Params {
242
243         public static String baseFolder;
244
245         @Option(name = "--help", aliases = { "-h"}, usage = "Show this help")
246         public Boolean help = false;
247
248         private final FileSettings FILESETTINGS = new FileSettings(new File(baseFolder, Constants.PROPERTIES_FILE).getAbsolutePath());
249
250         @Option(name = "--repositoriesFolder", usage = "Git Repositories Folder", metaVar = "PATH")
251         public String repositoriesFolder = FILESETTINGS.getString(Keys.git.repositoriesFolder, "git");
252
253         @Option(name = "--settings", usage = "Path to alternative settings", metaVar = "FILE")
254         public String settingsfile;
255
256         @Argument(index = 0, required = true, metaVar = "OUTPUTSERVICE", usage = "The destination/output ticket service")
257         public String outputServiceName;
258     }
259 }