2727
2828import java .io .PrintWriter ;
2929import java .io .StringWriter ;
30+ import java .net .URI ;
31+ import java .net .URISyntaxException ;
32+ import java .nio .file .FileSystemNotFoundException ;
33+ import java .nio .file .Files ;
3034import java .nio .file .Path ;
3135import java .nio .file .Paths ;
36+ import java .nio .file .ProviderNotFoundException ;
37+ import java .security .CodeSource ;
3238import java .util .List ;
3339import java .util .Objects ;
3440import java .util .Optional ;
@@ -51,6 +57,10 @@ public class CommandLine {
5157 protected static final String GENERATE_COMMAND = "generate" ;
5258 protected static final String OPEN_COMMAND = "open" ;
5359 protected static final String PLUGIN_COMMAND = "plugin" ;
60+ private static final String CONFIG_DIRECTORY = "config" ;
61+ private static final String PLUGINS_DIRECTORY = "plugins" ;
62+ private static final String DEFAULT_CONFIG_FILE_NAME = "allure.yml" ;
63+ private static final String LIB_DIRECTORY = "lib" ;
5464
5565 private final MainCommand mainCommand ;
5666 private final ServeCommand serveCommand ;
@@ -80,20 +90,76 @@ public CommandLine(final Commands commands) {
8090 }
8191
8292 public static void main (final String [] args ) throws InterruptedException {
83- final String allureHome = System .getenv ("APP_HOME" );
84- final CommandLine commandLine ;
85- if (Objects .isNull (allureHome )) {
86- commandLine = new CommandLine ((Path ) null );
87- LOGGER .info ("APP_HOME is not set, using default configuration" );
88- } else {
89- commandLine = new CommandLine (Paths .get (allureHome ));
93+ final Optional <Path > allureHome = resolveAllureHome (System .getenv ("APP_HOME" ));
94+ if (!allureHome .isPresent ()) {
95+ LOGGER .info ("Allure home is not set, using default configuration" );
9096 }
97+ final CommandLine commandLine = new CommandLine (allureHome .orElse (null ));
9198 final ExitCode exitCode = commandLine
9299 .parse (args )
93100 .orElseGet (commandLine ::run );
94101 System .exit (exitCode .getCode ());
95102 }
96103
104+ static Optional <Path > resolveAllureHome (final String allureHome , final URI codeSource ) {
105+ if (Objects .nonNull (allureHome )) {
106+ return Optional .of (Paths .get (allureHome ));
107+ }
108+ return inferAllureHome (codeSource );
109+ }
110+
111+ private static Optional <Path > resolveAllureHome (final String allureHome ) {
112+ if (Objects .nonNull (allureHome )) {
113+ return Optional .of (Paths .get (allureHome ));
114+ }
115+ return getCodeSource ()
116+ .flatMap (CommandLine ::inferAllureHome );
117+ }
118+
119+ private static Optional <URI > getCodeSource () {
120+ try {
121+ return Optional .ofNullable (CommandLine .class .getProtectionDomain ().getCodeSource ())
122+ .map (CodeSource ::getLocation )
123+ .map (location -> {
124+ try {
125+ return location .toURI ();
126+ } catch (URISyntaxException e ) {
127+ LOGGER .debug ("Could not resolve commandline location" , e );
128+ return null ;
129+ }
130+ });
131+ } catch (SecurityException e ) {
132+ LOGGER .debug ("Could not access commandline location" , e );
133+ return Optional .empty ();
134+ }
135+ }
136+
137+ private static Optional <Path > inferAllureHome (final URI codeSource ) {
138+ try {
139+ final Path location = Paths .get (codeSource ).toAbsolutePath ().normalize ();
140+ final Path lib = Files .isDirectory (location ) ? location : location .getParent ();
141+ if (Objects .isNull (lib )
142+ || Objects .isNull (lib .getFileName ())
143+ || !LIB_DIRECTORY .equals (lib .getFileName ().toString ())) {
144+ return Optional .empty ();
145+ }
146+ final Path home = lib .getParent ();
147+ return isAllureHome (home )
148+ ? Optional .of (home )
149+ : Optional .empty ();
150+ } catch (IllegalArgumentException | FileSystemNotFoundException | ProviderNotFoundException
151+ | SecurityException e ) {
152+ LOGGER .debug ("Could not infer Allure home from commandline location {}" , codeSource , e );
153+ return Optional .empty ();
154+ }
155+ }
156+
157+ private static boolean isAllureHome (final Path home ) {
158+ return Objects .nonNull (home )
159+ && Files .isRegularFile (home .resolve (CONFIG_DIRECTORY ).resolve (DEFAULT_CONFIG_FILE_NAME ))
160+ && Files .isDirectory (home .resolve (PLUGINS_DIRECTORY ));
161+ }
162+
97163 public Optional <ExitCode > parse (final String ... args ) {
98164 if (args .length == 0 ) {
99165 printUsage (commander );
0 commit comments