001/* 002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.golo.cli.command; 011 012import com.beust.jcommander.Parameter; 013import com.beust.jcommander.Parameters; 014import com.beust.jcommander.converters.IParameterSplitter; 015 016import java.io.File; 017import java.net.MalformedURLException; 018import java.net.URL; 019import java.net.URLClassLoader; 020import java.util.List; 021import java.util.LinkedList; 022import java.util.Collections; 023import java.util.Arrays; 024 025import org.eclipse.golo.compiler.GoloClassLoader; 026 027/** 028 * Manage the classpath and initialize the class loader. 029 */ 030@Parameters(resourceBundle = "commands") 031public class ClasspathOption { 032 033 /** 034 * The system property to define the path. 035 */ 036 public static final String PROPERTY = "golo.class.path"; 037 038 /** 039 * The environment variable used to define the path. 040 */ 041 public static final String ENV = "GOLOPATH"; 042 private static final List<String> DEFAULT = Collections.singletonList("."); 043 private static final String SEP = System.getProperty("path.separator", ":"); 044 045 private static class ClasspathSplitter implements IParameterSplitter { 046 private static final String RE = String.format("[,%s]", SEP); 047 public List<String> split(String value) { 048 return Arrays.asList(value.split(RE)); 049 } 050 } 051 052 @Parameter(names = "--classpath", variableArity = true, descriptionKey = "classpath", splitter = ClasspathSplitter.class) 053 List<String> classpath = new LinkedList<>(); 054 055 private static URLClassLoader primaryClassLoader(List<String> classpath) throws MalformedURLException { 056 URL[] urls = new URL[classpath.size()]; 057 for (int i = 0; i < classpath.size(); i++) { 058 urls[i] = new File(classpath.get(i)).toURI().toURL(); 059 } 060 return new URLClassLoader(urls); 061 } 062 063 /** 064 * Create a golo classloader using the given classpath list. 065 * <p> 066 * If {@code classpath} is empty, packages from the {@code PROPERTY} system property are used, then from 067 * {@code ENV} environment variable if no property is defined. Finally, the current directory is used if no other path 068 * is defined. 069 * The current thread class loader is set to the created golo class loader. 070 */ 071 public static GoloClassLoader initGoloClassLoader(List<String> classpath) throws MalformedURLException { 072 URLClassLoader primaryClassLoader = primaryClassLoader(initClassPath(classpath)); 073 GoloClassLoader loader = new GoloClassLoader(primaryClassLoader); 074 Thread.currentThread().setContextClassLoader(loader); 075 return loader; 076 } 077 078 private static List<String> initClassPath(List<String> init) { 079 // priority CLI > property > env > default 080 List<String> classpath = init; 081 if (classpath.isEmpty()) { 082 classpath = getFromEnv(System.getProperty(PROPERTY)); 083 } 084 if (classpath.isEmpty()) { 085 classpath = getFromEnv(System.getenv(ENV)); 086 } 087 if (classpath.isEmpty()) { 088 // XXX: should "." be used in any case or only if no other path is given? 089 classpath = DEFAULT; 090 } 091 System.setProperty(PROPERTY, String.join(SEP, classpath)); 092 return classpath; 093 } 094 095 private static List<String> getFromEnv(String value) { 096 if (value == null) { 097 return Collections.emptyList(); 098 } 099 return Arrays.asList(value.split(SEP)); 100 } 101 102 /** 103 * Init the class loader using the parsed command line option. 104 */ 105 public GoloClassLoader initGoloClassLoader() throws MalformedURLException { 106 return initGoloClassLoader(this.classpath); 107 } 108}