aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/shell/Shell.java
blob: 2cae24ec15346413b3e7818abf77fbdf8044de84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.shell;

import java.util.logging.Logger;

/**
 * <p>Represents an OS shell, such as "cmd" on Windows or "sh" on Unix-like
 * platforms. Currently, Linux and Windows XP are supported.</p>
 *
 * <p>This class encapsulates shell-specific logic, like how to
 * create a command line that uses the shell to invoke another command.
 */
public abstract class Shell {

  private static final Logger log =
    Logger.getLogger("com.google.devtools.build.lib.shell.Shell");
  
  private static final Shell platformShell;

  static {
    final String osName = System.getProperty("os.name");
    if ("Linux".equals(osName)) {
      platformShell = new SHShell();
    } else if ("Windows XP".equals(osName)) {
      platformShell = new WindowsCMDShell();
    } else {
      log.severe("OS not supported; will not be able to execute commands");
      platformShell = null;
    }
    log.config("Loaded shell support '" + platformShell +
               "' for OS '" + osName + "'");
  }

  private Shell() {
    // do nothing
  }

  /**
   * @return {@link Shell} subclass appropriate for the current platform
   * @throws UnsupportedOperationException if no such subclass exists
   */
  public static Shell getPlatformShell() {
    if (platformShell == null) {
      throw new UnsupportedOperationException("OS is not supported");
    }
    return platformShell;
  }

  /**
   * Creates a command line suitable for execution by
   * {@link Runtime#exec(String[])} from the given command string,
   * a command line which uses a shell appropriate for a particular
   * platform to execute the command (e.g. "/bin/sh" on Linux).
   *
   * @param command command for which to create a command line
   * @return String[] suitable for execution by
   *  {@link Runtime#exec(String[])}
   */
  public abstract String[] shellify(final String command);


  /**
   * Represents the <code>sh</code> shell commonly found on Unix-like
   * operating systems, including Linux.
   */
  private static final class SHShell extends Shell {

    /**
     * <p>Returns a command line which uses <code>cmd</code> to execute
     * the {@link Command}. Given the command <code>foo bar baz</code>,
     * for example, this will return a String array corresponding
     * to the command line:</p>
     *
     * <p><code>/bin/sh -c "foo bar baz"</code></p>
     *
     * <p>That is, it always returns a 3-element array.</p>
     *
     * @param command command for which to create a command line
     * @return String[] suitable for execution by
     *  {@link Runtime#exec(String[])}
     */
    @Override public String[] shellify(final String command) {
      if (command == null || command.length() == 0) {
        throw new IllegalArgumentException("command is null or empty");
      }
      return new String[] { "/bin/sh", "-c", command };
    }

  }

  /**
   * Represents the Windows command shell <code>cmd</code>.
   */
  private static final class WindowsCMDShell extends Shell {

    /**
     * <p>Returns a command line which uses <code>cmd</code> to execute
     * the {@link Command}. Given the command <code>foo bar baz</code>,
     * for example, this will return a String array corresponding
     * to the command line:</p>
     *
     * <p><code>cmd /S /C "foo bar baz"</code></p>
     *
     * <p>That is, it always returns a 4-element array.</p>
     *
     * @param command command for which to create a command line
     * @return String[] suitable for execution by
     *  {@link Runtime#exec(String[])}
     */
    @Override public String[] shellify(final String command) {
      if (command == null || command.length() == 0) {
        throw new IllegalArgumentException("command is null or empty");
      }
      return new String[] { "cmd", "/S", "/C", command };
    }

  }

}