package hudson.plugins.javanet_uploader; import hudson.EnvVars; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.BuildListener; import hudson.model.Result; import hudson.model.AbstractProject; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; import hudson.tasks.BuildStepDescriptor; import org.kohsuke.jnt.JNFile; import org.kohsuke.jnt.JNFileFolder; import org.kohsuke.jnt.JNProject; import org.kohsuke.jnt.JavaNet; import org.kohsuke.jnt.ProcessingException; import org.kohsuke.stapler.DataBoundConstructor; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; /** * {@link Publisher} that uploads files to java.net documents and files section. * * @author Kohsuke Kawaguchi */ public class JNUploaderPublisher extends Recorder { /** * Name of the java.net project to post a file to. */ public final String project; private final List<Entry> entries; @DataBoundConstructor public JNUploaderPublisher(String project, List<Entry> entries) { this.project = project; this.entries = entries; } public List<Entry> getEntries() { return entries; } public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.BUILD; } public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException { if(build.getResult()== Result.FAILURE) { // build failed. don't post return true; } try { listener.getLogger().println("Connecting to java.net"); JavaNet jn = JavaNet.connect(); JNProject project = jn.getProject(this.project); if(!project.exists()) { listener.error("No such project exists: "+project); build.setResult(Result.FAILURE); return true; } EnvVars envVars = build.getEnvironment(listener); for (Entry e : entries) { if(e.sourceFile.trim().length()==0) { listener.getLogger().println("Configuration error: no file is specified for upload"); build.setResult(Result.FAILURE); return true; } if(e.filePath.contains("/servlets/ProjectDocumentList?")) { // some people tried to specify URL here listener.getLogger().println("Configuration error: specify a folder path like '/foo/bar/zot' in the destination, not URL"); build.setResult(Result.FAILURE); } listener.getLogger().println("Uploading "+e.sourceFile+" to java.net"); String expanded = Util.replaceMacro(e.sourceFile, envVars); FilePath[] src = build.getWorkspace().list(expanded); if(src.length==0) throw new ProcessingException("No such file exists: "+ expanded); if(src.length==1) { String folderPath = Util.replaceMacro(e.filePath,envVars); JNFileFolder folder = project.getFolder(folderPath); if(folder!=null) { // this looks like a valid folder name, so just upload into it upload(folder, src[0].getName(), src[0], e, envVars, listener); } else { // assume that this is a full path name int idx = folderPath.lastIndexOf('/'); if(idx<0) throw new ProcessingException(folderPath+" doesn't have a file name"); String fileName = folderPath.substring(idx+1); folderPath = folderPath.substring(0,idx); folder = getFolder(project, folderPath); upload(folder, fileName, src[0], e, envVars, listener); } } else { String folderPath = Util.replaceMacro(e.filePath,envVars); JNFileFolder folder = getFolder(project,folderPath); for( FilePath s : src ) upload(folder, s.getName(), s, e, envVars, listener); } } } catch (ProcessingException e) { e.printStackTrace(listener.error("Failed to access java.net")); build.setResult(Result.FAILURE); } catch (IOException e) { e.printStackTrace(listener.error("Failed to upload files")); build.setResult(Result.FAILURE); } return true; } private void upload(JNFileFolder folder, String fileName, FilePath src, Entry e, Map<String, String> envVars, BuildListener listener) throws ProcessingException, IOException, InterruptedException { JNFile file = folder.getFiles().get(fileName); if( file!=null ) { file.delete(); } // java.net upload occasionally fails for no good reason, so retry for a few times under a certain situation for( int retryCount=0; ; retryCount++) { InputStream in = src.read(); try { folder.uploadFile(fileName, Util.replaceMacro(e.description,envVars), e.status, in, "application/octet-stream"); return; } catch (ProcessingException x) { if(x.getMessage().contains("timed out") && retryCount<3) { // retry for a few times in case of time out listener.error("Upload timed out. Retrying after 10 seconds"); Thread.sleep(10*1000); continue; } throw x; } finally { in.close(); } } } /** * Gets the {@link JNFileFolder} and do the error checking. */ private JNFileFolder getFolder(JNProject project, String folderPath) throws ProcessingException { JNFileFolder folder = project.getFolder(folderPath); if(folder==null) throw new ProcessingException("No such folder "+folderPath+" on project "+this.project); return folder; } @Extension public static class DescriptorImpl extends BuildStepDescriptor<Publisher> { public String getDisplayName() { return "Publish artifacts to java.net"; } public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; } } }