001/*
002 * Copyright 2012-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.cli.command.options;
018
019import java.io.File;
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.List;
023
024import joptsimple.OptionSet;
025
026import org.springframework.boot.cli.util.ResourceUtils;
027import org.springframework.util.Assert;
028
029/**
030 * Extract source file options (anything following '--' in an {@link OptionSet}).
031 *
032 * @author Phillip Webb
033 * @author Dave Syer
034 * @author Greg Turnquist
035 * @author Andy Wilkinson
036 */
037public class SourceOptions {
038
039        private final List<String> sources;
040
041        private final List<?> args;
042
043        /**
044         * Create a new {@link SourceOptions} instance.
045         * @param options the source option set
046         */
047        public SourceOptions(OptionSet options) {
048                this(options, null);
049        }
050
051        /**
052         * Create a new {@link SourceOptions} instance.
053         * @param arguments the source arguments
054         */
055        public SourceOptions(List<?> arguments) {
056                this(arguments, null);
057        }
058
059        /**
060         * Create a new {@link SourceOptions} instance. If it is an error to pass options that
061         * specify non-existent sources, but the default paths are allowed not to exist (the
062         * paths are tested before use). If default paths are provided and the option set
063         * contains no source file arguments it is not an error even if none of the default
064         * paths exist).
065         * @param optionSet the source option set
066         * @param classLoader an optional classloader used to try and load files that are not
067         * found in the local filesystem
068         */
069        public SourceOptions(OptionSet optionSet, ClassLoader classLoader) {
070                this(optionSet.nonOptionArguments(), classLoader);
071        }
072
073        private SourceOptions(List<?> nonOptionArguments, ClassLoader classLoader) {
074                List<String> sources = new ArrayList<String>();
075                int sourceArgCount = 0;
076                for (Object option : nonOptionArguments) {
077                        if (option instanceof String) {
078                                String filename = (String) option;
079                                if ("--".equals(filename)) {
080                                        break;
081                                }
082                                List<String> urls = new ArrayList<String>();
083                                File fileCandidate = new File(filename);
084                                if (fileCandidate.isFile()) {
085                                        urls.add(fileCandidate.getAbsoluteFile().toURI().toString());
086                                }
087                                else if (!isAbsoluteWindowsFile(fileCandidate)) {
088                                        urls.addAll(ResourceUtils.getUrls(filename, classLoader));
089                                }
090                                for (String url : urls) {
091                                        if (isSource(url)) {
092                                                sources.add(url);
093                                        }
094                                }
095                                if (isSource(filename)) {
096                                        if (urls.isEmpty()) {
097                                                throw new IllegalArgumentException("Can't find " + filename);
098                                        }
099                                        else {
100                                                sourceArgCount++;
101                                        }
102                                }
103                        }
104                }
105                this.args = Collections.unmodifiableList(
106                                nonOptionArguments.subList(sourceArgCount, nonOptionArguments.size()));
107                Assert.isTrue(!sources.isEmpty(), "Please specify at least one file");
108                this.sources = Collections.unmodifiableList(sources);
109        }
110
111        private boolean isAbsoluteWindowsFile(File file) {
112                return isWindows() && file.isAbsolute();
113        }
114
115        private boolean isWindows() {
116                return File.separatorChar == '\\';
117        }
118
119        private boolean isSource(String name) {
120                return name.endsWith(".java") || name.endsWith(".groovy");
121        }
122
123        public List<?> getArgs() {
124                return this.args;
125        }
126
127        public String[] getArgsArray() {
128                return this.args.toArray(new String[this.args.size()]);
129        }
130
131        public List<String> getSources() {
132                return this.sources;
133        }
134
135        public String[] getSourcesArray() {
136                return this.sources.toArray(new String[this.sources.size()]);
137        }
138
139}