2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package gov.nasa.jpf.util;
21 import java.io.BufferedReader;
23 import java.io.FileNotFoundException;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.io.PrintWriter;
27 import java.io.Reader;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
35 * utility class for JPF site configuration related functions. This is partially redundant to Config since
36 * it is used during bootstrapping, and gov.nasa.jpf.Config might not be in the classpath yet. It mostly
37 * differs in terms of key/value expansion, which is only partially supported here.
39 * NOTE - this class is not allowed to use any JPF specific types
41 public class JPFSiteUtils {
43 //--- preparse support - we need this if we use app properties to locat lower level property files
45 static Pattern keyValPattern = Pattern.compile("^[ \t]*([^# \t][^ \t]*)[ \t]*=[ \t]*(.+?)[ \t]*$");
48 * minimal parsing - only local key, system property and and config_path expansion
49 * NOTE this stops after finding the key, and it doesn't add the file to the 'sources'
51 public static String getMatchFromFile (String pathName, String lookupKey){
53 Pattern lookupPattern = Pattern.compile(lookupKey);
55 File propFile = new File(pathName);
56 if (!propFile.isFile()){
60 HashMap<String, String> map = new HashMap<String, String>();
61 String dir = propFile.getParent();
65 map.put("config_path", dir);
68 FileReader fr = new FileReader(propFile);
69 BufferedReader br = new BufferedReader(fr);
71 for (String line = br.readLine(); line != null; line = br.readLine()) {
72 Matcher m = keyValPattern.matcher(line);
74 String key = m.group(1);
75 String val = m.group(2);
77 val = expandLocal(val, map);
79 if ((key.length() > 0) && (val.length() > 0)) {
80 // check for continuation lines
81 if (val.charAt(val.length() - 1) == '\\') {
82 val = val.substring(0, val.length() - 1).trim();
83 for (line = br.readLine(); line != null; line = br.readLine()) {
85 int len = line.length();
86 if ((len > 0) && (line.charAt(len - 1) == '\\')) {
87 line = line.substring(0, line.length() - 1).trim();
88 val += expandLocal(line, map);
90 val += expandLocal(line, map);
96 Matcher lookupMatcher = lookupPattern.matcher(key);
97 if (lookupMatcher.matches()) {
101 if (key.charAt(key.length() - 1) == '+') {
102 key = key.substring(0, key.length() - 1);
103 String v = map.get(key);
107 } else if (key.charAt(0) == '+') {
108 key = key.substring(1);
109 String v = map.get(key);
121 } catch (FileNotFoundException fnfx) {
123 } catch (IOException iox) {
131 * this returns the contents of a config source in-order, without expanding values or keys
133 public static List<Pair<String,String>> getRawEntries (Reader reader) throws IOException {
134 ArrayList<Pair<String,String>> list = new ArrayList<Pair<String,String>>();
135 BufferedReader br = new BufferedReader(reader);
137 for (String line = br.readLine(); line != null; line = br.readLine()) {
138 Matcher m = keyValPattern.matcher(line);
140 String key = m.group(1);
141 String val = m.group(2);
143 if ((key.length() > 0) && (val.length() > 0)) {
144 // check for continuation lines
145 if (val.charAt(val.length() - 1) == '\\') {
146 val = val.substring(0, val.length() - 1).trim();
147 for (line = br.readLine(); line != null; line = br.readLine()) {
149 int len = line.length();
150 if ((len > 0) && (line.charAt(len - 1) == '\\')) {
151 line = line.substring(0, line.length() - 1).trim();
160 list.add( new Pair<String,String>(key,val));
168 // simple non-recursive, local key and system property expander
169 private static String expandLocal (String s, HashMap<String,String> map) {
171 if (s == null || s.length() == 0) {
175 while ((i = s.indexOf("${", j)) >= 0) {
176 if ((j = s.indexOf('}', i)) > 0) {
177 String k = s.substring(i + 2, j);
184 v = System.getProperty(k);
188 s = s.substring(0, i) + v + s.substring(j + 1, s.length());
191 s = s.substring(0, i) + s.substring(j + 1, s.length());
200 public static File getCoreDir (File siteProps){
201 if (siteProps != null){
202 String path = getMatchFromFile(siteProps.getAbsolutePath(), "jpf-core");
204 File coreDir = new File(path);
205 if (coreDir.isDirectory()) {
213 public static File getSiteCoreDir (String[] args){
214 File siteProps = getSiteProperties( args);
215 return getCoreDir( siteProps);
219 * get location of jpf-core from site.properties
220 * @return null if it doesn't exist
222 public static File getSiteCoreDir() {
223 File siteProps = getStandardSiteProperties();
224 return getCoreDir( siteProps);
228 * find project properties (jpf.properties) from current dir
230 public static File getCurrentProjectProperties() {
231 File d = new File(System.getProperty("user.dir"));
233 File f = new File(d, "jpf.properties");
237 d = d.getParentFile();
244 static Pattern idPattern = Pattern.compile("^[ \t]*([^# \t][^ \t]*)[ \t]*=[ \t]*\\$\\{config_path\\}");
246 static String projectId;
249 * look for a "<id> = ${config_path}" entry in current dir/jpf.properties
250 * this looks recursively upwards
251 * @return null if no jpf.properties found
253 public static String getCurrentProjectId (){
254 if (projectId == null) {
255 File propFile = getCurrentProjectProperties();
257 if (propFile != null) {
259 FileReader fr = new FileReader(propFile);
260 BufferedReader br = new BufferedReader(fr);
262 for (String line = br.readLine(); line != null; line = br.readLine()) {
263 Matcher m = idPattern.matcher(line);
265 projectId = m.group(1);
270 } catch (FileNotFoundException fnfx) {
272 } catch (IOException iox) {
281 public static boolean isFreeArg (String a){
282 return ((a != null) && (a.length() > 0) && a.charAt(0) != '+' && a.charAt(0) != '-');
285 public static File getSiteProperties (String[] args){
286 //--- 1. check for a +site=<path> argument up to first free arg
287 for (int i=0; i<args.length; i++){
290 if (a.startsWith("+site=")) {
291 String path = a.substring(6).trim();
292 return new File(path);
299 //--- 2. check if the first free arg is an application property file (*.jpf), and it contains a 'site=..' setting
300 for (int i=0; i<args.length; i++){
303 if (a.matches("[^+-].*\\.jpf")) {
304 String path = getMatchFromFile(a, "site");
306 return new File(path);
313 //--- 3. finally, check upwards from the current dir up to the home dir
314 return JPFSiteUtils.getStandardSiteProperties();
318 * locate the site.properties. Start with the current dir, go upwards until the
319 * user.home is reached. If site.properties isn't found there, look for '.jpf' and
320 * 'jpf' dirs within the home dir. If no site.properties is found there either, give up
322 public static File getStandardSiteProperties(){
323 String userDir = System.getProperty("user.dir");
324 File dir = new File(userDir);
325 for (; dir != null; dir = dir.getParentFile()) {
326 File f = new File(dir, "site.properties");
332 String[] jpfDirCandidates = { ".jpf", "jpf" };
333 String userHome = System.getProperty("user.home");
335 for (String jpfDir : jpfDirCandidates){
336 dir = new File(userHome, jpfDir);
337 if (dir.isDirectory()) {
338 File f = new File(dir, "site.properties");
348 public static String getGlobalSitePropertiesPath() {
349 String userHome = System.getProperty("user.home");
350 String globalPath = userHome + File.separator + ".jpf"
351 + File.separator + "site.properties";
355 public static List<Pair<String,String>> getRawEntries (File siteProps){
356 FileReader fr = null;
357 if (siteProps.isFile()) {
359 fr = new FileReader(siteProps);
360 List<Pair<String,String>> entries = getRawEntries(fr);
365 } catch (IOException iox) {
367 try { fr.close(); } catch (IOException _ignore){}
371 return new ArrayList<Pair<String,String>>();
375 * this returns a list of all the project ids in the 'extensions' entries (also
376 * handles accumulated 'extensions+=.." entries
378 public static List<String> getExtensions (List<Pair<String,String>> entries){
379 ArrayList<String> list = new ArrayList<String>();
381 for (Pair<String,String> p : entries){
382 if (p._1.startsWith("extensions")){
383 for (String pid : p._2.split("[,;]")){
385 if (pid.charAt(0) == '$'){
386 pid = pid.substring(2, pid.length()-1);
397 public static boolean addProject (File siteProps, String projectId, File projectDir, boolean isExt){
398 List<Pair<String,String>> entries = getRawEntries(siteProps);
399 List<String> extensions = getExtensions(entries);
401 if ("jpf-core".equals(projectId)){ // jpf-core always has to be in the extensions list
406 FileUtils.ensureDirs(siteProps);
407 String projectPath = FileUtils.asCanonicalUserPathName(projectDir.getAbsolutePath());
409 PrintWriter pw = new PrintWriter(siteProps);
411 pw.println("# auto-generated JPF site properties");
414 boolean alreadyThere = false;
415 for (Pair<String, String> e : entries) {
416 if (!"extensions".equals(e._1)) {
421 if (projectId.equals(e._1)) {
423 // Hmm, not sure its best to use absolute pathnames here (e.g. when doing local site installs)
424 pw.println(projectPath);
426 // check if we have to update extensions
427 if (extensions.contains(projectId)){
429 extensions.remove(projectId);
432 extensions.add(projectId);
443 extensions.add(projectId);
448 pw.println(projectPath);
452 pw.print("extensions = ");
454 boolean isFirst = true;
455 for (String e : extensions) {
469 } catch (IOException iox) {
470 iox.printStackTrace();