source: rtems-eclipse-plug-in/org.rtems.cdt/src/org/rtems/cdt/Storage.java @ 98d4bf1

Last change on this file since 98d4bf1 was 98d4bf1, checked in by Sebastian Huber <sebastian.huber@…>, on 03/18/09 at 13:53:00

Support space characters in paths and options.

  • Property mode set to 100644
File size: 12.5 KB
Line 
1/*
2 * Copyright (c) 2008 Embedded Brains GmbH and others.
3 *
4 *   Embedded Brains GmbH
5 *   Obere Lagerstr. 30
6 *   D-82178 Puchheim
7 *   Germany
8 *   rtems@embedded-brains.de
9 *
10 * All rights reserved.  This program and the accompanying materials are made
11 * available under the terms of the Eclipse Public License Version 1.0 ("EPL")
12 * which accompanies this distribution and is available at
13 *
14 *   http://www.eclipse.org/legal/epl-v10.html
15 *
16 * For purposes of the EPL, "Program" will mean the Content.
17 *
18 * Contributors:
19 *
20 *   Sebastian Huber (Embedded Brains GmbH) - Initial API and implementation.
21 */
22
23package org.rtems.cdt;
24
25import java.io.BufferedReader;
26import java.io.File;
27import java.io.IOException;
28import java.io.InputStream;
29import java.io.InputStreamReader;
30import java.util.LinkedList;
31import java.util.List;
32import java.util.Map;
33
34import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext;
35import org.eclipse.cdt.build.internal.core.scannerconfig.CfgDiscoveredPathManager;
36import org.eclipse.cdt.core.model.CoreModel;
37import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
38import org.eclipse.cdt.core.settings.model.ICProjectDescription;
39import org.eclipse.cdt.managedbuilder.core.IConfiguration;
40import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
41import org.eclipse.core.resources.IMarker;
42import org.eclipse.core.resources.IProject;
43import org.eclipse.core.resources.IResource;
44import org.eclipse.core.runtime.CoreException;
45import org.eclipse.core.runtime.IPath;
46import org.eclipse.core.runtime.Path;
47import org.eclipse.core.runtime.Platform;
48import org.eclipse.core.runtime.QualifiedName;
49
50public class Storage {
51        private static final String OPTION_SEPARATOR = "\0";
52
53        private static final String VALUE_START_TOKEN = "\t";
54
55        private static final int EXPECT_OPTION = 0;
56
57        private static final int EXPECT_COMMAND = 1;
58
59        private static final int EXPECT_KEY = 2;
60
61        private static final int TOOL_COMPLETE = 3;
62
63        public static String getPreference( String key) {
64                return Activator.getDefault().getPreferenceStore().getString( key);
65        }
66
67        public static String getPristineProperty( IProject project, String key) {
68                String value = null;
69
70                try {
71                        value = project.getPersistentProperty( new QualifiedName( "", key));
72                } catch (CoreException e) {
73                        e.printStackTrace();
74                }
75
76                return value;
77        }
78
79        public static String getProperty( IProject project, String key) {
80                String value = getPristineProperty( project, key);
81
82                if (value == null) {
83                        if (key.startsWith( Constants.TOOL_KEY_PREFIX)) {
84                                changePlatform( project, Constants.PLATFORM_DEFAULT);
85                        } else {
86                                value = getPreference( key);
87                                setProperty( project, key, value);
88                        }
89                }
90
91                return value;
92        }
93
94        public static void setProperty( IProject project, String key, String value) {
95                try {
96                        project.setPersistentProperty( new QualifiedName( "", key), value);
97                } catch (CoreException e) {
98                        e.printStackTrace();
99                }
100        }
101
102        public static IConfiguration [] getConfigurations( IProject project) {
103                ICProjectDescription pd = CoreModel.getDefault().getProjectDescription( project);
104
105                ICConfigurationDescription cds [] = pd.getConfigurations();
106                IConfiguration cfgs [] = new IConfiguration [cds.length];
107                for (int i = 0; i < cds.length; ++i) {
108                        cfgs [i] = ManagedBuildManager.getConfigurationForDescription( cds [i]);
109                }
110
111                return cfgs;
112        }
113
114        public static IConfiguration getActiveConfiguration( IProject project) {
115                ICProjectDescription pd = CoreModel.getDefault().getProjectDescription( project);
116
117                ICConfigurationDescription cd = pd.getActiveConfiguration();
118                IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription( cd);
119
120                return cfg;
121        }
122
123        public static String prependToPath( String path, String part) {
124                if (path == null || path.length()==0) {
125                        return part;
126                } else {
127                        return part + Constants.PATH_SEPARATOR + path;
128                }
129        }
130
131        public static String prependToPathByPreference( String path, String key) {
132                String basePath = getPreference( key);
133
134                if (basePath != null) {
135                        IPath part = new Path( basePath).append( "bin");
136
137                        return prependToPath( path, part.toOSString());
138                }
139
140                return path;
141        }
142
143        public static String prependToPathByProperty( IProject project, String path, String key) {
144                String basePath = getProperty( project, key);
145
146                if (basePath != null) {
147                        IPath part = new Path( basePath).append( "bin");
148
149                        return prependToPath( path, part.toOSString());
150                }
151
152                return path;
153        }
154
155        public static String getPlatform( IProject project) {
156                return getPristineProperty( project, Constants.PLATFORM_KEY);
157        }
158       
159        public static void setPlatform( IProject project, String platform) {
160                setProperty( project, Constants.PLATFORM_KEY, platform);
161        }
162
163        public static void clearPlatform( IProject project) {
164                setPlatform( project, null);
165
166                // Delete discovered paths for all configurations of the project
167                for (IConfiguration cfg : getConfigurations( project)) {
168                        CfgDiscoveredPathManager.getInstance().removeDiscoveredInfo(
169                                project,
170                                new CfgInfoContext( cfg)
171                        );
172                }
173        }
174
175        public static void changePlatform( IProject project, String newPlatform) {
176                String platform = getPlatform( project);
177
178                // Check if we have already the requested platform
179                if (platform != null && platform == newPlatform) {
180                        // Nothing to do
181                        return;
182                }
183
184                // Set new platform
185                setPlatform( project, newPlatform);
186
187                // Update path prepends
188                String path = null;
189                if (Platform.getOS().equals( Platform.OS_WIN32)) {
190                        if (newPlatform.equals( Constants.PLATFORM_CYGWIN)) {
191                                path = prependToPathByPreference( path, Constants.CYGWIN_PATH_KEY);
192                        } else {
193                                path = prependToPathByPreference( path, Constants.MINGW_PATH_KEY);
194                                path = prependToPathByPreference( path, Constants.MSYS_PATH_KEY);
195                        }
196                }
197                path = prependToPathByProperty( project, path, Constants.BASE_PATH_KEY);
198                setProperty( project, Constants.PATH_PREPEND_KEY, path);
199
200                // Update tools
201                updateTools( project, newPlatform);
202        }
203
204        private static void updateTools( IProject project, String platform) {
205                String bspPath = getProperty( project, Constants.BSP_PATH_KEY);
206                IPath make = new Path( "make");
207                List<String> options = new LinkedList<String>();
208                boolean error = false;
209               
210                // Set tools to default values
211                updateTool( project, Constants.TOOL_ARCHIVER_KEY, "ar", options);
212                updateTool( project, Constants.TOOL_ASSEMBLER_KEY, "as", options);
213                updateTool( project, Constants.TOOL_COMPILER_CPP_KEY, "g++", options);
214                updateTool( project, Constants.TOOL_COMPILER_C_KEY, "gcc", options);
215                updateTool( project, Constants.TOOL_LINKER_CPP_KEY, "g++", options);
216                updateTool( project, Constants.TOOL_LINKER_C_KEY, "gcc", options);
217               
218                // Delete markers for this unit
219                deleteMarkers( project, Constants.MARKER_ID_TOOL_DISCOVERY);
220               
221                // Translate path if necessary
222                if (Platform.getOS().equals( Platform.OS_WIN32)) {
223                        if (platform.equals( Constants.PLATFORM_CYGWIN)) {
224                                String s [] = bspPath.split( ":");
225                                if (s.length > 0) {
226                                        bspPath = bspPath.replaceFirst( "^" + s [0] + ":", "/cygdrive/" + s [0]);
227                                }
228                        }
229                        bspPath = bspPath.replaceAll( "\\\\", "/");
230                }
231
232                // Create make process builder
233                ProcessBuilder pb = new ProcessBuilder();
234
235                // Change working directory to the Makefile location
236                pb.directory( Activator.getDefault().getMakefileLocation().toFile());
237
238                // Update path environment variable
239                Map<String, String> env = pb.environment();
240                String path = env.get( Constants.PATH_VARIABLE_NAME);
241                String part = getProperty( project, Constants.PATH_PREPEND_KEY);
242                path = Storage.prependToPath( path, part);
243                env.put( Constants.PATH_VARIABLE_NAME, path);
244
245                // On Windows we have to search for the make program in the new path environment
246                if (Platform.getOS().equals( Platform.OS_WIN32)) {
247                        String parts [] = path.split( Constants.PATH_SEPARATOR);
248                        boolean found = false;
249                       
250                        for (String p : parts) {
251                                IPath makeCandidate = new Path( p).append( "make.exe");
252                                File file = new File( makeCandidate.toOSString());
253                               
254                                if (file.exists()) {
255                                        make = makeCandidate;
256                                        found = true;
257                                        break;
258                                }
259                        }
260                       
261                        if (!found) {
262                                createMarker(
263                                        project,
264                                        Constants.MARKER_ID_TOOL_DISCOVERY,
265                                        "make program not found, check your Cygwin or MinGW settings in the RTEMS preferences"
266                                );
267                        }
268                }
269
270                // Set command line
271                String makeArgument = Constants.BSP_PATH_MAKE_VARIABLE + "=" + bspPath.replaceAll( " ", "\\\\ ");
272                pb.command(
273                        make.toOSString(),
274                        makeArgument
275                );
276
277                // Start make process and parse its output
278                Process p = null;
279                try {
280                        p = pb.start();
281                        InputStream is = p.getInputStream();
282                        BufferedReader br = new BufferedReader( new InputStreamReader( is));
283                        String line = br.readLine();
284                        String key = null;
285                        String command = null;
286                        int state = EXPECT_KEY;
287                        while (line != null) {
288                                switch (state) {
289                                        case EXPECT_OPTION:
290                                                if (line.startsWith( VALUE_START_TOKEN)) {
291                                                        options.add( line.substring( 1));
292                                                } else {
293                                                        state = TOOL_COMPLETE;
294                                                        continue;
295                                                }
296                                                break;
297                                        case EXPECT_COMMAND:
298                                                if (line.startsWith( VALUE_START_TOKEN)) {
299                                                        command = line.substring( 1);
300                                                        state = EXPECT_OPTION;
301                                                } else {
302                                                        throw new IOException( "unexpected line format");
303                                                }
304                                                break;
305                                        case EXPECT_KEY:
306                                                if (line.length() > Constants.TOOL_KEY_PREFIX.length()) {
307                                                        key = line;
308                                                        state = EXPECT_COMMAND;
309                                                } else {
310                                                        throw new IOException( "unexpected line format");
311                                                }
312                                                break;
313                                        case TOOL_COMPLETE:
314                                                updateTool( project, key, command, options);
315                                                options.clear();
316                                                state = EXPECT_KEY;
317                                                continue;
318                                        default:
319                                                throw new IOException( "unexpected state");
320                                }
321                                line = br.readLine();
322                        }
323                        if (state == EXPECT_OPTION) {
324                                updateTool( project, key, command, options);
325                        }
326                } catch (IOException e) {
327                        error = true;
328                        createMarker(
329                                project,
330                                Constants.MARKER_ID_TOOL_DISCOVERY,
331                                "make output parse error: " + e.getMessage()
332                        );
333                } finally {
334                        while (true) {
335                                try {
336                                        p.waitFor();
337                                        break;
338                                } catch (InterruptedException e) {
339                                        continue;
340                                }
341                        }
342                }
343               
344                // Check exit status
345                if (p.exitValue() != 0) {
346                        error = true;
347                        createMarker(
348                                project,
349                                Constants.MARKER_ID_TOOL_DISCOVERY,
350                                "make invokation `" + make.toOSString() + " " + makeArgument + "' returned with error status " + p.exitValue()
351                        );
352                }
353               
354                // Check error
355                if (error) {
356                        // Clear platform to trigger an update again if someone changed a preference or property value
357                        setPlatform( project, null);
358                }
359        }
360
361        private static void updateTool( IProject project, String toolKey, String command, List<String> options) {
362                List<String> filteredOptions = new LinkedList<String>();
363
364                // Filter options
365                if (toolKey.startsWith( Constants.COMPILER_KEY_PREFIX) || toolKey.startsWith( Constants.LINKER_KEY_PREFIX)) {
366                        for (String option : options) {
367                                if (!(option.length() == 0 || option.trim().matches( "^-c|-O[0123s]|-g|-W[\\w-]*$"))) {
368                                        filteredOptions.add( option);
369                                }
370                        }
371                } else {
372                        filteredOptions = options;
373                }
374
375                // Transform filtered option list into option string value
376                String optionsValue = new String();
377                if (!options.isEmpty()) {
378                        optionsValue = filteredOptions.get( 0);
379                        filteredOptions.remove( 0);
380                }
381                for (String option : filteredOptions) {
382                        if (option.indexOf( ' ') != -1) {
383                                option = "\"" + option + "\"";
384                        }
385                        optionsValue += OPTION_SEPARATOR + option;
386                }
387
388                // Set properties
389                setProperty( project, toolKey, command);
390                setProperty( project, toolKey + Constants.TOOL_OPTIONS_KEY_POSTFIX, optionsValue);
391        }
392
393        public static String [] getToolOptions( IProject project, String toolKey) {
394                String optionsValue = getProperty( project, toolKey + Constants.TOOL_OPTIONS_KEY_POSTFIX);
395
396                return optionsValue.split( OPTION_SEPARATOR);
397        }
398       
399        public static void createMarker( IProject project, String id, String message) {
400                createMarker( project, id, message, IMarker.SEVERITY_ERROR);
401        }
402        public static void createMarker( IProject project, String id, String message, int severity)     {       
403                try {
404                        IMarker marker = project.createMarker( IMarker.PROBLEM);
405                        marker.setAttribute( IMarker.LOCATION, id);
406                        marker.setAttribute( IMarker.MESSAGE, message);
407                        marker.setAttribute( IMarker.SEVERITY, severity);
408                } catch (CoreException e) {
409                        e.printStackTrace();
410                }
411
412        }
413       
414        public static void deleteMarkers( IProject project, String id) {
415                try {
416                        IMarker[] markers = project.findMarkers( IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
417                        if (markers != null) {
418                                for (IMarker m : markers) {
419                                        if (m.getResource().equals( project) && m.getAttribute( IMarker.LOCATION, "").equals( id)) {
420                                                m.delete();
421                                        }
422                                }
423                        }
424                } catch (CoreException e) {
425                        e.printStackTrace();
426                }
427
428        }
429
430        private Storage() {
431                // Do nothing
432        }
433}
Note: See TracBrowser for help on using the repository browser.