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