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 */
009package org.eclipse.golo.cli.command;
010
011import com.beust.jcommander.Parameter;
012import com.beust.jcommander.Parameters;
013import java.io.IOException;
014import java.io.InputStream;
015import java.nio.file.FileSystems;
016import java.nio.file.Files;
017import java.nio.file.Path;
018import java.nio.file.PathMatcher;
019import java.nio.file.Paths;
020import java.util.LinkedList;
021import java.util.List;
022import java.util.stream.Collectors;
023import org.eclipse.golo.cli.command.spi.CliCommand;
024import org.eclipse.golo.compiler.GoloClassLoader;
025import org.eclipse.golo.compiler.GoloCompilationException;
026
027import static gololang.Messages.message;
028
029@Parameters(commandNames = {"shebang"}, resourceBundle = "commands", commandDescriptionKey = "golo")
030public class ShebangCommand implements CliCommand {
031
032  @Parameter(descriptionKey = "arguments", required = true)
033  List<String> arguments = new LinkedList<>();
034
035  @Override
036  public void execute() throws Throwable {
037    Path script = Paths.get(arguments.get(0));
038    while (Files.isSymbolicLink(script)) {
039      script = Files.readSymbolicLink(script);
040    }
041    Path basedir = dirName(script);
042    GoloClassLoader loader = ClasspathOption.initGoloClassLoader(classpath(basedir));
043    try {
044      loadOtherGoloFiles(loader, basedir, script);
045      callRun(loadGoloFile(loader, script), this.arguments.toArray(new String[this.arguments.size()]));
046    } catch (GoloCompilationException e) {
047      handleCompilationException(e);
048    }
049  }
050
051  private static Path dirName(Path file) {
052    if (!file.isAbsolute()) {
053      return file.toAbsolutePath().getParent();
054    }
055    return file.getParent();
056  }
057
058  private static boolean sameFile(Path path1, Path path2) {
059    return path1.toAbsolutePath().compareTo(path2.toAbsolutePath()) == 0;
060  }
061
062  private List<String> classpath(Path basedir) throws IOException {
063    PathMatcher jarFiles = FileSystems.getDefault().getPathMatcher("glob:**/*.jar");
064    return Files.walk(basedir)
065        .filter(path -> jarFiles.matches(path))
066        .map(path -> path.toAbsolutePath().toString())
067        .collect(Collectors.toList());
068  }
069
070  private void loadOtherGoloFiles(GoloClassLoader loader, Path basedir, Path script) throws IOException {
071    PathMatcher goloFiles = FileSystems.getDefault().getPathMatcher("glob:**/*.golo");
072    Files.walk(basedir)
073        .filter(path -> goloFiles.matches(path) && !sameFile(path, script))
074        .forEach(path -> loadGoloFile(loader, path));
075  }
076
077  private Class<?> loadGoloFile(GoloClassLoader loader, Path path) {
078    try (InputStream is = Files.newInputStream(path)) {
079      Path filename = path.getFileName();
080      if (filename != null) {
081        return loader.load(filename.toString(), is);
082      } else {
083        throw new RuntimeException(message("not_regular_file", path));
084      }
085    } catch (IOException e) {
086      throw new RuntimeException(e);
087    }
088  }
089
090}