Project

General

Profile

Download (7.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2020 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.drush;
10

    
11
import java.io.File;
12
import java.io.IOException;
13
import java.io.InputStream;
14
import java.net.URI;
15
import java.net.URISyntaxException;
16
import java.util.ArrayList;
17
import java.util.Arrays;
18
import java.util.List;
19
import java.util.Scanner;
20
import java.util.regex.Matcher;
21
import java.util.regex.Pattern;
22

    
23
import org.apache.commons.io.IOUtils;
24
import org.apache.commons.lang3.SystemUtils;
25
import org.apache.log4j.Level;
26
import org.apache.log4j.Logger;
27

    
28
/**
29
 * @author a.kohlbecker
30
 * @since Jul 31, 2020
31
 */
32
public class DrushExecuter {
33

    
34
    public static final Logger logger = Logger.getLogger(DrushExecuter.class);
35

    
36

    
37
    public URI getSiteURI() {
38
        return siteURI;
39
    }
40

    
41
    public void setSiteURI(URI siteURI) {
42
        this.siteURI = siteURI;
43
    }
44

    
45
    public File getDrupalRoot() {
46
        return drupalRoot;
47
    }
48

    
49
    public void setDrupalRoot(File drupalRoot) {
50
        this.drupalRoot = drupalRoot;
51
    }
52

    
53
    public URI siteURI = null;
54

    
55
    public File drupalRoot = null;
56

    
57
    public DrushExecuter() throws IOException, InterruptedException {
58
       findDrushCommand();
59
    }
60

    
61
    /**
62
     * List indexes returned from <code>DrushExecuter.execute(DrushCommand cmd, String... value)</code>:
63
     *
64
     * <ol>
65
     * <li>major</li>
66
     * <li>minor</li>
67
     * <li>patch</li>
68
     * <ol>
69
     */
70
    public static DrushCommand version = new DrushCommand(Arrays.asList("--version"), "Drush Version\\s+:\\s+(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)", null);
71

    
72

    
73
    public static DrushCommand help = new DrushCommand(Arrays.asList("help"), null, null);
74

    
75
    public static DrushCommand coreStatus = new DrushCommand(Arrays.asList("core-status"), null, null);
76

    
77
    /**
78
     * List indexes returned from <code>DrushExecuter.execute(DrushCommand cmd, String... value)</code>:
79
     * Multiple matches are possible:
80
     * <ol>
81
     * <li>value</li>
82
     * <li>value</li>
83
     * <li>value</li>
84
     * <ol>
85
     */
86
    public static DrushCommand variableGet = new DrushCommand(Arrays.asList("vget", "%s"), ".*:\\s+'(?<value>.*)'", null);
87

    
88
    /**
89
     * List indexes returned from <code>DrushExecuter.execute(DrushCommand cmd, String... value)</code>:
90
     * Multiple matches are possible:
91
     * <ol>
92
     * <li>value</li>
93
     * <li>status</li>
94
     * <ol>
95
     */
96
    public static DrushCommand variableSet = new DrushCommand(Arrays.asList("--yes", "vset", "%s", "%s"), null,  "[^\\\"]*\\\"(?<value>.*)\\\"\\.\\s+\\[(?<status>\\w+)\\]");
97

    
98
    /**
99
     * @throws IOException if an I/O error occurs in the ProcessBuilder
100
     * @throws InterruptedException if the Process was interrupted
101
     */
102
    private void findDrushCommand() throws IOException, InterruptedException {
103

    
104
        if(SystemUtils.IS_OS_WINDOWS) {
105
            throw new RuntimeException("not yet implmented for Windows");
106
        }
107

    
108
        List<String> matches = execute(version);
109
        assert !matches.get(0).isEmpty() : "No suitable drush command found in the system";
110
        String majorVersion = matches.get(0);
111
        if(Integer.valueOf(majorVersion) < 8) {
112
            throw new RuntimeException("drush version >= 8 required");
113
        }
114

    
115
    }
116

    
117
    /**
118
     * @throws IOException if an I/O error occurs in the ProcessBuilder
119
     * @throws InterruptedException if the Process was interrupted
120
     */
121
    public List<String> execute(DrushCommand cmd, String ...value ) throws IOException, InterruptedException {
122

    
123
        List<String> executableWithArgs = new ArrayList<>();
124
        executableWithArgs.add("drush");
125

    
126
        if(drupalRoot != null) {
127
            executableWithArgs.add("--root="+drupalRoot.toString());
128
        }
129
        if(siteURI != null) {
130
            executableWithArgs.add("--uri=" + siteURI.toString());
131
        }
132
        int commandSubstitutions = 0;
133
        for(String arg  : cmd.args) {
134
            if(arg.contains("%s")) {
135
                executableWithArgs.add(String.format(arg, value[commandSubstitutions]));
136
                commandSubstitutions++;
137
            } else {
138
                executableWithArgs.add(arg);
139
            }
140
        }
141

    
142
        List<String> matches = new ArrayList<>();
143

    
144
        ProcessBuilder pb = new ProcessBuilder(executableWithArgs);
145
        logger.debug("Command: " + pb.command().toString());
146
        Process process = pb.start();
147
        int exitCode = process.waitFor();
148

    
149
        if(exitCode == 0) {
150
            String out = readExecutionResponse(matches, process.getInputStream(), cmd.outRegex);
151
            String error = readExecutionResponse(matches, process.getErrorStream(), cmd.errRegex);
152
            if(out != null && !out.isEmpty()) {
153
                logger.error(error);
154
            }
155
            if(error != null && !error.isEmpty()) {
156
                logger.error(error);
157
            }
158
        } else {
159
            throw new RuntimeException(IOUtils.toString(process.getErrorStream()));
160
        }
161
        return matches;
162
    }
163

    
164
    protected String readExecutionResponse(List<String> matches, InputStream stream, Pattern regex) throws IOException {
165
        String out;
166
        if(regex != null) {
167
            Scanner scanner = new Scanner(stream);
168
            while(true) {
169
                out = scanner.findWithinHorizon(regex, 0);
170
                if(out == null) {
171
                    break;
172
                }
173
                if(out != null) {
174
                    Matcher m = regex.matcher(out);
175
                    int patternMatchCount = 0;
176
                    while(m.find()) {
177
                        patternMatchCount++;
178
                        if(m.groupCount() > 0) {
179
                            for(int g = 1 ; g <= m.groupCount(); g++) {
180
                                matches.add(m.group(g));
181
                                logger.debug("match[" + patternMatchCount + "."+ g + "]: " + m.group(g));
182
                            }
183
                        } else {
184
                            matches.add(m.group(0));
185
                            logger.debug("entire pattern match[" + patternMatchCount + ".0]: " + m.group(0));
186
                        }
187
                    }
188
                }
189
            }
190
            scanner.close();
191
            return null;
192
        } else {
193
            out = IOUtils.toString(stream);
194
            logger.debug(out);
195
            return out;
196
        }
197

    
198
    }
199

    
200

    
201
    public static class DrushCommand {
202

    
203
        Pattern outRegex;
204
        Pattern errRegex;
205
        List<String> args = new ArrayList<>();
206

    
207
        public DrushCommand(List<String> args, String outRegex, String errRegex) {
208
            this.args = args;
209
            if(outRegex != null) {
210
                this.outRegex = Pattern.compile(outRegex, Pattern.MULTILINE);
211
            }
212
            if(errRegex != null) {
213
                this.errRegex = Pattern.compile(errRegex, Pattern.MULTILINE);
214
            }
215
        }
216
    }
217

    
218
    public static void main(String[] args) throws URISyntaxException  {
219
        DrushExecuter.logger.setLevel(Level.DEBUG);
220
        try {
221
            DrushExecuter dex = new DrushExecuter();
222
            dex.setDrupalRoot(new File("/home/andreas/workspaces/www/drupal-7"));
223
            dex.setSiteURI(new URI("http://edit.test/d7/caryophyllales/"));
224
//            dex.execute(coreStatus);
225
//            dex.execute(help);
226
//            dex.execute(variableGet, "cdm_webservice_url");
227
            dex.execute(variableSet, "cdm_webservice_url", "http://api.cybertaxonomy.org/cyprus/");
228
        } catch (IOException | InterruptedException | AssertionError e) {
229
            e.printStackTrace();
230
        }
231
    }
232
}
    (1-1/1)