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