/hudson-core/src/main/java/hudson/tasks/Shell.java

http://github.com/hudson/hudson · Java · 161 lines · 96 code · 20 blank · 45 comment · 9 complexity · cdf558ca094617263e93a99f40f97b35 MD5 · raw file

  1. /*
  2. * The MIT License
  3. *
  4. * Copyright (c) 2004-2011, 2011, Oracle Corporation, Kohsuke Kawaguchi, Jene Jasper, Yahoo! Inc., Nikita Levyankov
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. package hudson.tasks;
  25. import hudson.FilePath;
  26. import hudson.Functions;
  27. import hudson.Util;
  28. import hudson.Extension;
  29. import hudson.model.AbstractProject;
  30. import hudson.util.FormValidation;
  31. import net.sf.json.JSONObject;
  32. import org.kohsuke.stapler.DataBoundConstructor;
  33. import org.kohsuke.stapler.StaplerRequest;
  34. import org.kohsuke.stapler.QueryParameter;
  35. import java.util.List;
  36. import java.util.ArrayList;
  37. import java.util.Arrays;
  38. /**
  39. * Executes a series of commands by using a shell.
  40. *
  41. * @author Kohsuke Kawaguchi
  42. */
  43. public class Shell extends CommandInterpreter {
  44. @DataBoundConstructor
  45. public Shell(String command) {
  46. super(fixCrLf(command));
  47. }
  48. /**
  49. * Fix CR/LF and always make it Unix style.
  50. */
  51. private static String fixCrLf(String s) {
  52. // eliminate CR
  53. int idx;
  54. if (null != s) { //avoid potential NullPointerException if command is null.
  55. while ((idx = s.indexOf("\r\n")) != -1) {
  56. s = s.substring(0, idx) + s.substring(idx + 1);
  57. }
  58. }
  59. return s;
  60. }
  61. /**
  62. * Older versions of bash have a bug where non-ASCII on the first line
  63. * makes the shell think the file is a binary file and not a script. Adding
  64. * a leading line feed works around this problem.
  65. */
  66. private static String addCrForNonASCII(String s) {
  67. if(!s.startsWith("#!")) {
  68. if (s.indexOf('\n')!=0) {
  69. return "\n" + s;
  70. }
  71. }
  72. return s;
  73. }
  74. public String[] buildCommandLine(FilePath script) {
  75. if(command.startsWith("#!")) {
  76. // interpreter override
  77. int end = command.indexOf('\n');
  78. if(end<0) end=command.length();
  79. List<String> args = new ArrayList<String>();
  80. args.addAll(Arrays.asList(Util.tokenize(command.substring(0,end).trim())));
  81. args.add(script.getRemote());
  82. args.set(0,args.get(0).substring(2)); // trim off "#!"
  83. return args.toArray(new String[args.size()]);
  84. } else
  85. return new String[] { getDescriptor().getShellOrDefault(),"-xe",script.getRemote()};
  86. }
  87. protected String getContents() {
  88. return addCrForNonASCII(fixCrLf(command));
  89. }
  90. protected String getFileExtension() {
  91. return ".sh";
  92. }
  93. @Override
  94. public DescriptorImpl getDescriptor() {
  95. return (DescriptorImpl)super.getDescriptor();
  96. }
  97. @Extension
  98. public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
  99. /**
  100. * Shell executable, or null to default.
  101. */
  102. private String shell;
  103. public DescriptorImpl() {
  104. load();
  105. }
  106. public boolean isApplicable(Class<? extends AbstractProject> jobType) {
  107. return true;
  108. }
  109. public String getShell() {
  110. return shell;
  111. }
  112. public String getShellOrDefault() {
  113. if(shell==null)
  114. return Functions.isWindows() ?"sh":"/bin/sh";
  115. return shell;
  116. }
  117. public void setShell(String shell) {
  118. this.shell = Util.fixEmptyAndTrim(shell);
  119. save();
  120. }
  121. public String getDisplayName() {
  122. return Messages.Shell_DisplayName();
  123. }
  124. @Override
  125. public Builder newInstance(StaplerRequest req, JSONObject data) {
  126. return new Shell(data.getString("command"));
  127. }
  128. @Override
  129. public boolean configure(StaplerRequest req, JSONObject data) {
  130. setShell(req.getParameter("shell"));
  131. return true;
  132. }
  133. /**
  134. * Check the existence of sh in the given location.
  135. */
  136. public FormValidation doCheck(@QueryParameter String value) {
  137. // Executable requires admin permission
  138. return FormValidation.validateExecutable(value);
  139. }
  140. }
  141. }