~gephi.team/gephi/0.8.1

« back to all changes in this revision

Viewing changes to SettingsUpgrader/src/org/gephi/ui/upgrader/CopyFiles.java

  • Committer: Mathieu Bastian
  • Date: 2011-12-30 23:01:06 UTC
  • Revision ID: git-v1:5c95e7ab7992c455e7bb1a5eaa8596c2ace2fffa
Add settings upgrader module to import previous installation preferences

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright 2008-2010 Gephi
 
3
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
 
4
Website : http://www.gephi.org
 
5
 
 
6
This file is part of Gephi.
 
7
 
 
8
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
9
 
 
10
Copyright 2011 Gephi Consortium. All rights reserved.
 
11
 
 
12
The contents of this file are subject to the terms of either the GNU
 
13
General Public License Version 3 only ("GPL") or the Common
 
14
Development and Distribution License("CDDL") (collectively, the
 
15
"License"). You may not use this file except in compliance with the
 
16
License. You can obtain a copy of the License at
 
17
http://gephi.org/about/legal/license-notice/
 
18
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
 
19
specific language governing permissions and limitations under the
 
20
License.  When distributing the software, include this License Header
 
21
Notice in each file and include the License files at
 
22
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
 
23
License Header, with the fields enclosed by brackets [] replaced by
 
24
your own identifying information:
 
25
"Portions Copyrighted [year] [name of copyright owner]"
 
26
 
 
27
If you wish your version of this file to be governed by only the CDDL
 
28
or only the GPL Version 3, indicate your decision by adding
 
29
"[Contributor] elects to include this software in this distribution
 
30
under the [CDDL or GPL Version 3] license." If you do not indicate a
 
31
single choice of license, a recipient has the option to distribute
 
32
your version of this file under either the CDDL, the GPL Version 3 or
 
33
to extend the choice of license to its licensees as provided above.
 
34
However, if you add GPL Version 3 code and therefore, elected the GPL
 
35
Version 3 license, then the option applies only if the new code is
 
36
made subject to such option by the copyright holder.
 
37
 
 
38
Contributor(s):
 
39
 
 
40
Portions Copyrighted 2011 Gephi Consortium.
 
41
 */
 
42
package org.gephi.ui.upgrader;
 
43
 
 
44
import java.io.BufferedReader;
 
45
import java.io.File;
 
46
import java.io.FileInputStream;
 
47
import java.io.FileOutputStream;
 
48
import java.io.IOException;
 
49
import java.io.InputStream;
 
50
import java.io.InputStreamReader;
 
51
import java.io.OutputStream;
 
52
import java.io.Reader;
 
53
import java.util.HashSet;
 
54
import java.util.Set;
 
55
import org.openide.filesystems.FileUtil;
 
56
import org.openide.util.EditableProperties;
 
57
 
 
58
/**
 
59
 *
 
60
 * @author mbastian
 
61
 */
 
62
public class CopyFiles {
 
63
 
 
64
    private File sourceRoot;
 
65
    private File targetRoot;
 
66
    private EditableProperties currentProperties;
 
67
    private Set<String> includePatterns = new HashSet<String>();
 
68
    private Set<String> excludePatterns = new HashSet<String>();
 
69
 
 
70
    private CopyFiles(File source, File target) {
 
71
        this.sourceRoot = source;
 
72
        this.targetRoot = target;
 
73
        //Pattern files
 
74
        try {
 
75
            InputStream is = CopyFiles.class.getResourceAsStream("/org/gephi/ui/upgrader/gephi.import");
 
76
            Reader reader = new InputStreamReader(is, "utf-8"); // NOI18N
 
77
            readPatterns(reader);
 
78
            reader.close();
 
79
        } catch (IOException ex) {
 
80
        }
 
81
    }
 
82
 
 
83
    public static void copyDeep(File source, File target) throws IOException {
 
84
        CopyFiles copyFiles = new CopyFiles(source, target);
 
85
        System.out.println("Copying from: " + copyFiles.sourceRoot + "\nto: " + copyFiles.targetRoot);  //NOI18N
 
86
        copyFiles.copyFolder(copyFiles.sourceRoot);
 
87
    }
 
88
 
 
89
    private void copyFolder(File sourceFolder) throws IOException {
 
90
        File[] srcChildren = sourceFolder.listFiles();
 
91
        if (srcChildren == null) {
 
92
            System.err.println(sourceFolder + " is not a directory or is invalid.");  //NOI18N
 
93
            return;
 
94
        }
 
95
        for (File child : srcChildren) {
 
96
            if (child.isDirectory()) {
 
97
                copyFolder(child);
 
98
            } else {
 
99
                copyFile(child);
 
100
            }
 
101
        }
 
102
    }
 
103
 
 
104
    /** Copy given file to target root dir if matches include/exclude patterns.
 
105
     * If properties pattern is applicable, it copies only matching keys.
 
106
     * @param sourceFile source file
 
107
     * @throws java.io.IOException if copying fails
 
108
     */
 
109
    private void copyFile(File sourceFile) throws IOException {
 
110
        String relativePath = getRelativePath(sourceRoot, sourceFile);
 
111
        boolean includeFile = false;
 
112
        Set<String> includeKeys = new HashSet<String>();
 
113
        Set<String> excludeKeys = new HashSet<String>();
 
114
        for (String pattern : includePatterns) {
 
115
            if (pattern.contains("#")) {  //NOI18N
 
116
                includeKeys.addAll(matchingKeys(relativePath, pattern));
 
117
            } else {
 
118
                if (relativePath.matches(pattern)) {
 
119
                    includeFile = true;
 
120
                    includeKeys.clear();  // include entire file
 
121
                    break;
 
122
                }
 
123
            }
 
124
        }
 
125
        if (includeFile || !includeKeys.isEmpty()) {
 
126
            // check excludes
 
127
            for (String pattern : excludePatterns) {
 
128
                if (pattern.contains("#")) {  //NOI18N
 
129
                    excludeKeys.addAll(matchingKeys(relativePath, pattern));
 
130
                } else {
 
131
                    if (relativePath.matches(pattern)) {
 
132
                        includeFile = false;
 
133
                        includeKeys.clear();  // exclude entire file
 
134
                        break;
 
135
                    }
 
136
                }
 
137
            }
 
138
        }
 
139
//        System.out.println(String.format("%s, includeFile=%s, includeKeys=%s, excludeKeys=%s", new Object[]{relativePath, includeFile, includeKeys, excludeKeys}));  //NOI18N
 
140
        if (!includeFile && includeKeys.isEmpty()) {
 
141
            // nothing matches
 
142
            return;
 
143
        }
 
144
 
 
145
        File targetFile = new File(targetRoot, relativePath);
 
146
//        System.out.println(String.format("Path: %s", relativePath));  //NOI18N
 
147
        if (includeKeys.isEmpty() && excludeKeys.isEmpty()) {
 
148
            // copy entire file
 
149
            copyFile(sourceFile, targetFile);
 
150
        } else {
 
151
            if (!includeKeys.isEmpty()) {
 
152
                currentProperties.keySet().retainAll(includeKeys);
 
153
            }
 
154
            currentProperties.keySet().removeAll(excludeKeys);
 
155
            // copy just selected keys
 
156
//            System.out.println(String.format("  Only keys: %s", currentProperties.keySet()));
 
157
            OutputStream out = null;
 
158
            try {
 
159
                ensureParent(targetFile);
 
160
                out = new FileOutputStream(targetFile);
 
161
                currentProperties.store(out);
 
162
            } finally {
 
163
                if (out != null) {
 
164
                    out.close();
 
165
                }
 
166
            }
 
167
        }
 
168
    }
 
169
 
 
170
    /** Returns slash separated path relative to given root. */
 
171
    private static String getRelativePath(File root, File file) {
 
172
        String result = file.getAbsolutePath().substring(root.getAbsolutePath().length());
 
173
        result = result.replace('\\', '/');  //NOI18N
 
174
        if (result.startsWith("/") && !result.startsWith("//")) {  //NOI18N
 
175
            result = result.substring(1);
 
176
        }
 
177
        return result;
 
178
    }
 
179
 
 
180
    /** Copy source file to target file. It creates necessary sub folders.
 
181
     * @param sourceFile source file
 
182
     * @param targetFile target file
 
183
     * @throws java.io.IOException if copying fails
 
184
     */
 
185
    private static void copyFile(File sourceFile, File targetFile) throws IOException {
 
186
        ensureParent(targetFile);
 
187
        InputStream ins = null;
 
188
        OutputStream out = null;
 
189
        try {
 
190
            ins = new FileInputStream(sourceFile);
 
191
            out = new FileOutputStream(targetFile);
 
192
            FileUtil.copy(ins, out);
 
193
        } finally {
 
194
            if (ins != null) {
 
195
                ins.close();
 
196
            }
 
197
            if (out != null) {
 
198
                out.close();
 
199
            }
 
200
        }
 
201
    }
 
202
 
 
203
    /** Creates parent of given file, if doesn't exist. */
 
204
    private static void ensureParent(File file) throws IOException {
 
205
        final File parent = file.getParentFile();
 
206
        if (parent != null && !parent.exists()) {
 
207
            if (!parent.mkdirs()) {
 
208
                throw new IOException("Cannot create folder: " + parent.getAbsolutePath());  //NOI18N
 
209
            }
 
210
        }
 
211
    }
 
212
 
 
213
    /** Returns set of keys matching given pattern.
 
214
     * @param relativePath path relative to sourceRoot
 
215
     * @param propertiesPattern pattern like file.properties#keyPattern
 
216
     * @return set of matching keys, never null
 
217
     * @throws IOException if properties cannot be loaded
 
218
     */
 
219
    private Set<String> matchingKeys(String relativePath, String propertiesPattern) throws IOException {
 
220
        Set<String> matchingKeys = new HashSet<String>();
 
221
        String[] patterns = propertiesPattern.split("#", 2);
 
222
        String filePattern = patterns[0];
 
223
        String keyPattern = patterns[1];
 
224
        if (relativePath.matches(filePattern)) {
 
225
            if (currentProperties == null) {
 
226
                currentProperties = getProperties(relativePath);
 
227
            }
 
228
            for (String key : currentProperties.keySet()) {
 
229
                if (key.matches(keyPattern)) {
 
230
                    matchingKeys.add(key);
 
231
                }
 
232
            }
 
233
        }
 
234
        return matchingKeys;
 
235
    }
 
236
 
 
237
    /** Returns properties from relative path.
 
238
     * @param relativePath relative path
 
239
     * @return properties from relative path.
 
240
     * @throws IOException if cannot open stream
 
241
     */
 
242
    private EditableProperties getProperties(String relativePath) throws IOException {
 
243
        EditableProperties properties = new EditableProperties(false);
 
244
        InputStream in = null;
 
245
        try {
 
246
            in = new FileInputStream(new File(sourceRoot, relativePath));
 
247
            properties.load(in);
 
248
        } finally {
 
249
            if (in != null) {
 
250
                in.close();
 
251
            }
 
252
        }
 
253
        return properties;
 
254
    }
 
255
 
 
256
    /** Reads the include/exclude set from a given reader.
 
257
     * @param r reader
 
258
     */
 
259
    private void readPatterns(Reader r) throws IOException {
 
260
        BufferedReader buf = new BufferedReader(r);
 
261
        for (;;) {
 
262
            String line = buf.readLine();
 
263
            if (line == null) {
 
264
                break;
 
265
            }
 
266
            line = line.trim();
 
267
            if (line.length() == 0 || line.startsWith("#")) {  //NOI18N
 
268
                continue;
 
269
            }
 
270
            if (line.startsWith("include ")) {  //NOI18N
 
271
                line = line.substring(8);
 
272
                if (line.length() > 0) {
 
273
                    includePatterns.addAll(parsePattern(line));
 
274
                }
 
275
            } else if (line.startsWith("exclude ")) {  //NOI18N
 
276
                line = line.substring(8);
 
277
                if (line.length() > 0) {
 
278
                    excludePatterns.addAll(parsePattern(line));
 
279
                }
 
280
            } else {
 
281
                throw new java.io.IOException("Wrong line: " + line);  //NOI18N
 
282
            }
 
283
        }
 
284
    }
 
285
 
 
286
    enum ParserState {
 
287
 
 
288
        START,
 
289
        IN_KEY_PATTERN,
 
290
        AFTER_KEY_PATTERN,
 
291
        IN_BLOCK
 
292
    }
 
293
 
 
294
    /** Parses given compound string pattern into set of single patterns.
 
295
     * @param pattern compound pattern in form filePattern1#keyPattern1#|filePattern2#keyPattern2#|filePattern3
 
296
     * @return set of single patterns containing just one # (e.g. [filePattern1#keyPattern1, filePattern2#keyPattern2, filePattern3])
 
297
     */
 
298
    private static Set<String> parsePattern(String pattern) {
 
299
        Set<String> patterns = new HashSet<String>();
 
300
        if (pattern.contains("#")) {  //NOI18N
 
301
            StringBuilder partPattern = new StringBuilder();
 
302
            ParserState state = ParserState.START;
 
303
            int blockLevel = 0;
 
304
            for (int i = 0; i < pattern.length(); i++) {
 
305
                char c = pattern.charAt(i);
 
306
                switch (state) {
 
307
                    case START:
 
308
                        if (c == '#') {
 
309
                            state = ParserState.IN_KEY_PATTERN;
 
310
                            partPattern.append(c);
 
311
                        } else if (c == '(') {
 
312
                            state = ParserState.IN_BLOCK;
 
313
                            blockLevel++;
 
314
                            partPattern.append(c);
 
315
                        } else if (c == '|') {
 
316
                            patterns.add(partPattern.toString());
 
317
                            partPattern = new StringBuilder();
 
318
                        } else {
 
319
                            partPattern.append(c);
 
320
                        }
 
321
                        break;
 
322
                    case IN_KEY_PATTERN:
 
323
                        if (c == '#') {
 
324
                            state = ParserState.AFTER_KEY_PATTERN;
 
325
                        } else {
 
326
                            partPattern.append(c);
 
327
                        }
 
328
                        break;
 
329
                    case AFTER_KEY_PATTERN:
 
330
                        if (c == '|') {
 
331
                            state = ParserState.START;
 
332
                            patterns.add(partPattern.toString());
 
333
                            partPattern = new StringBuilder();
 
334
                        } else {
 
335
                            assert false : "Wrong OptionsExport pattern " + pattern + ". Only format like filePattern1#keyPattern#|filePattern2 is supported.";  //NOI18N
 
336
                        }
 
337
                        break;
 
338
                    case IN_BLOCK:
 
339
                        partPattern.append(c);
 
340
                        if (c == ')') {
 
341
                            blockLevel--;
 
342
                            if (blockLevel == 0) {
 
343
                                state = ParserState.START;
 
344
                            }
 
345
                        }
 
346
                        break;
 
347
                }
 
348
            }
 
349
            patterns.add(partPattern.toString());
 
350
        } else {
 
351
            patterns.add(pattern);
 
352
        }
 
353
        return patterns;
 
354
    }
 
355
}