1. Jan Lahoda
  2. jackpot30

Commits

Jan Lahoda  committed b305d8e

Support for indexing in Hudson continuous builder

  • Participants
  • Parent commits e7611c5
  • Branches default

Comments (0)

Files changed (15)

File .hgignore

View file
 ^server/hudson/work$
 ^server/hudson/target$
 ^server/hudson/data/compiler/.*.jar$
+^server/hudson/data/compiler/indexer/*$
 ^server/hudson/data/compiler/hints$

File hudson/trunk

View file
 gzip <build/updates/updates.xml >build/updates/updates.xml.gz
 
 (cd cmdline/compiler; call_ant copy-to-hudson) || exit
+(cd server/indexer; call_ant copy-to-hudson) || exit
 (cd server/hudson; mvn clean package) || exit
 (cd cmdline/tool; call_ant create-standalone-tool) || exit
 

File server/hudson/src/main/java/org/netbeans/api/jackpot/hudson/IndexBuilder.java

View file
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2010 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.api.jackpot.hudson;
+
+import hudson.DescriptorExtensionList;
+import hudson.ExtensionPoint;
+import hudson.Launcher;
+import hudson.model.AbstractBuild;
+import hudson.model.BuildListener;
+import hudson.model.Describable;
+import hudson.model.Descriptor;
+import hudson.model.Hudson;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ *
+ * @author lahvac
+ */
+public abstract class IndexBuilder implements Describable<IndexBuilder>, ExtensionPoint {
+
+    public IndexBuilderDescriptor getDescriptor() {
+        return (IndexBuilderDescriptor)Hudson.getInstance().getDescriptor(getClass());
+    }
+
+    public abstract boolean index(File cacheDir, AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException;
+
+    public static DescriptorExtensionList<IndexBuilder, IndexBuilderDescriptor> all() {
+        return Hudson.getInstance().getDescriptorList(IndexBuilder.class);
+    }
+
+    public static abstract class IndexBuilderDescriptor extends Descriptor<IndexBuilder> {
+        protected IndexBuilderDescriptor(Class<? extends IndexBuilder> clazz) {
+            super(clazz);
+        }
+        protected IndexBuilderDescriptor() {
+        }
+    }
+
+}
+

File server/hudson/src/main/java/org/netbeans/modules/jackpot30/hudson/Cache.java

View file
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 1997-2009 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.jackpot30.hudson;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author lahvac
+ */
+public class Cache {
+
+    public static final int VERSION = 1;
+
+    private static File standaloneCacheRoot;
+    private static Map<String, Cache> name2Cache = new HashMap<String, Cache>();
+
+    public static Cache findCache(String indexName) {
+        Cache cache = name2Cache.get(indexName);
+
+        if (cache == null) {
+            name2Cache.put(indexName, cache = new Cache(indexName));
+        }
+
+        return cache;
+    }
+
+    private final String name;
+
+    private Cache(String name) {
+        this.name = name;
+    }
+    
+    public File findCacheRoot(URL sourceRoot) throws IOException {
+        try {
+            sourceRoot = sourceRoot.toURI().normalize().toURL();
+        } catch (URISyntaxException ex) {
+            Logger.getLogger(Cache.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        if (standaloneCacheRoot != null) {
+            return getDataFolder(sourceRoot, name);
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public static void setStandaloneCacheRoot(File standaloneCacheRoot) {
+        Cache.standaloneCacheRoot = standaloneCacheRoot;
+    }
+
+
+    private static Properties segments;
+    private static Map<String, String> invertedSegments;
+    private static int index = 0;
+
+    private static final String SEGMENTS_FILE = "segments";      //NOI18N
+    private static final String SLICE_PREFIX = "s";              //NOI18N
+
+    private static void loadSegments () throws IOException {
+        if (segments == null) {
+            final File folder = standaloneCacheRoot;
+            assert folder != null;
+            segments = new Properties ();
+            invertedSegments = new HashMap<String,String> ();
+            final File segmentsFile =  new File(folder, SEGMENTS_FILE);
+            if (segmentsFile.canRead()) {
+                final InputStream in = new FileInputStream(segmentsFile);
+                try {
+                    segments.load (in);
+                } finally {
+                    in.close();
+                }
+            }
+            for (Entry<Object, Object> entry : segments.entrySet()) {
+                String segment = (String) entry.getKey();
+                String root = (String) entry.getValue();
+                invertedSegments.put(root,segment);
+                try {
+                    index = Math.max (index,Integer.parseInt(segment.substring(SLICE_PREFIX.length())));
+                } catch (NumberFormatException nfe) {
+                    throw new IllegalStateException(nfe); //TODO: maybe just log the exception?
+                }
+            }
+        }
+    }
+
+    public static Iterable<? extends String> knownSourceRoots() throws IOException {
+        loadSegments();
+
+        List<String> known = new LinkedList<String>();
+        
+        for (String segment : segments.stringPropertyNames()) {
+            known.add(segment);
+        }
+
+        return known;
+    }
+
+    public static File sourceRootForKey(String segment) throws IOException {
+        loadSegments();
+
+        try {
+            return new File(new File(new URI(segments.getProperty(segment))).getAbsolutePath());
+        } catch (URISyntaxException ex) {
+            throw new IOException(ex);
+        }
+    }
+
+
+    private static void storeSegments () throws IOException {
+        final File folder = standaloneCacheRoot;
+        assert folder != null;
+        final File segmentsFile = new File(folder, SEGMENTS_FILE);
+        segmentsFile.getParentFile().mkdirs();
+        final OutputStream out = new FileOutputStream(segmentsFile);
+        try {
+            segments.store(out,null);
+        } finally {
+            out.close();
+        }
+    }
+
+    private static synchronized File getDataFolder (final URL root, String name) throws IOException {
+        loadSegments ();
+        final String rootName = root.toExternalForm();
+        String slice = invertedSegments.get (rootName);
+        if ( slice == null) {
+            slice = SLICE_PREFIX + (++index);
+            while (segments.getProperty(slice) != null) {
+                slice = SLICE_PREFIX + (++index);
+            }
+            segments.put (slice,rootName);
+            invertedSegments.put(rootName, slice);
+            storeSegments ();
+        }
+        final File folder = standaloneCacheRoot;
+        return new File(new File(folder, slice), name);
+    }
+
+    private static synchronized File getCacheFolder () {
+        return standaloneCacheRoot;
+    }
+
+
+}

File server/hudson/src/main/java/org/netbeans/modules/jackpot30/hudson/ClearIndexProperty.java

View file
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2010 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hudson;
+
+import hudson.Extension;
+import hudson.model.Action;
+import hudson.model.Hudson;
+import hudson.model.Job;
+import hudson.model.JobProperty;
+import hudson.model.JobPropertyDescriptor;
+import hudson.model.Project;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import javax.servlet.ServletException;
+import net.sf.json.JSONObject;
+import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerResponse;
+
+/**
+ *
+ * @author lahvac
+ */
+public class ClearIndexProperty extends JobProperty<Job<?, ?>> {
+    
+    @Override
+    public Collection<? extends Action> getJobActions(Job<?, ?> job) {
+        return Collections.singleton(new ClearIndexAction(job));
+    }
+
+    public static final class ClearIndexAction implements Action {
+
+        private final Job<?, ?> job;
+
+        public ClearIndexAction(Job<?, ?> job) {
+            this.job = job;
+        }
+
+        public String getIconFileName() {
+            return "folder-delete.gif";
+        }
+
+        public String getDisplayName() {
+            return "Clear Indices";
+        }
+
+        public String getUrlName() {
+            return "clearIndex";
+        }
+
+        public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+            String jobName = job.getName();
+            Project<?, ?> prj = Hudson.getInstance().getItemByFullName(jobName, Project.class);
+            File cacheRoot = Cache.findCache("clear-workspace").findCacheRoot(prj.getSomeWorkspace().toURI().toURL()).getParentFile();
+
+            deleteRecursivelly(cacheRoot);
+            
+            rsp.forwardToPreviousPage(req);
+        }
+
+        private static void deleteRecursivelly(File f) {
+            File[] files = f.listFiles();
+
+            if (files != null) {
+                for (File c : files) {
+                    deleteRecursivelly(c);
+                }
+            }
+
+            f.delete();
+        }
+    }
+
+    @Extension // this marker indicates Hudson that this is an implementation of an extension point.
+    public static final class ClearIndexPropertyDescription extends JobPropertyDescriptor  {
+
+        @Override
+        public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+            return new ClearIndexProperty();
+        }
+
+        @Override
+        public String getDisplayName() {
+            return "Clear Indices Desc";
+        }
+
+        @Override
+        public boolean isApplicable(Class<? extends Job> jobType) {
+            return Project.class.isAssignableFrom(jobType);
+        }
+
+    }
+}

File server/hudson/src/main/java/org/netbeans/modules/jackpot30/hudson/IndexingBuilder.java

View file
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2010 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hudson;
+
+import hudson.Extension;
+import hudson.Launcher;
+import hudson.model.AbstractBuild;
+import hudson.model.BuildListener;
+import hudson.model.Descriptor;
+import hudson.model.Descriptor.FormException;
+import hudson.model.Hudson;
+import hudson.tasks.Builder;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.sf.json.JSONObject;
+import net.sf.json.JSONSerializer;
+import org.kohsuke.stapler.DataBoundConstructor;
+import org.kohsuke.stapler.StaplerRequest;
+import org.netbeans.api.jackpot.hudson.IndexBuilder;
+import org.netbeans.api.jackpot.hudson.IndexBuilder.IndexBuilderDescriptor;
+
+/**
+ *
+ * @author lahvac
+ */
+public final class IndexingBuilder extends Builder {
+
+    private final String projectName;
+    private final Set<IndexBuilder> indexers;
+    
+    public IndexingBuilder(StaplerRequest req, JSONObject json) throws FormException {
+        projectName = json.getString("projectName");
+        indexers = new HashSet<IndexBuilder>();
+
+        for (IndexBuilderDescriptor desc : IndexBuilder.all()) {
+            if (json.containsKey(desc.getJsonSafeClassName())) {
+                indexers.add(desc.newInstance(req, json.getJSONObject(desc.getJsonSafeClassName())));
+            }
+        }
+    }
+
+    @DataBoundConstructor
+    public IndexingBuilder(String projectName, Set<IndexBuilder> indexers) {
+        this.projectName = projectName;
+        this.indexers = indexers;
+    }
+
+    public String getProjectName() {
+        return projectName;
+    }
+
+    public Set<IndexBuilder> getIndexers() {
+        return indexers;
+    }
+
+    @Override
+    public DescriptorImpl getDescriptor() {
+        return (DescriptorImpl) super.getDescriptor();
+    }
+
+    public boolean isIndexerEnabled(String indexer) {
+        for (IndexBuilder b : indexers) {
+            if (indexer.equals(b.getDescriptor().getJsonSafeClassName()))
+                return true;
+        }
+        
+        return false;
+    }
+
+    @Override
+    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
+        boolean success = true;
+
+        for (IndexBuilder indexer : getIndexers()) {
+            success &= indexer.index(getDescriptor().getCacheDir(), build, launcher, listener);
+        }
+        //XXX:
+        File info = new File(Cache.findCache("jackpot30").findCacheRoot(build.getWorkspace().toURI().toURL()), "info");
+        String jsonContent = readFully(info);
+        JSONObject json = JSONObject.fromObject(jsonContent);
+
+        if (!projectName.equals(json.get("displayName"))) {
+            json.put("displayName", projectName);
+            write(info, JSONSerializer.toJSON(json).toString());
+        }
+
+        return success;
+    }
+
+    private static String readFully(File file) throws IOException {
+        Reader in = null;
+        StringBuilder result = new StringBuilder();
+
+        try {
+            in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
+
+            int read;
+
+            while ((read = in.read()) != (-1)) {
+                result.append((char) read);
+            }
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException ex) {
+                    Logger.getLogger(IndexBuilder.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
+        }
+
+        return result.toString();
+    }
+
+    private static void write(File file, String content) throws IOException {
+        Writer out = null;
+        StringBuilder result = new StringBuilder();
+
+        try {
+            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
+            out.write(content);
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException ex) {
+                    Logger.getLogger(IndexBuilder.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
+        }
+    }
+
+    @Extension // this marker indicates Hudson that this is an implementation of an extension point.
+    public static final class DescriptorImpl extends Descriptor<Builder> {
+
+        private File cacheDir;
+
+        public DescriptorImpl() {
+            Cache.setStandaloneCacheRoot(cacheDir = new File(Hudson.getInstance().getRootDir(), "index").getAbsoluteFile());
+        }
+
+        public File getCacheDir() {
+            return cacheDir;
+        }
+
+        @Override
+        public Builder newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+            return new IndexingBuilder(req, formData);
+        }
+
+        @Override
+        public String getDisplayName() {
+            return "Run Indexers";
+        }
+
+        public List<? extends IndexBuilderDescriptor> getIndexers() {
+            return IndexBuilder.all();
+        }
+    }
+
+}

File server/hudson/src/main/java/org/netbeans/modules/jackpot30/hudson/JackpotIndexBuilder.java

View file
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2010 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hudson;
+
+import hudson.Extension;
+import hudson.Launcher;
+import hudson.Proc;
+import hudson.model.AbstractBuild;
+import hudson.model.BuildListener;
+import hudson.scm.ChangeLogSet.AffectedFile;
+import hudson.scm.ChangeLogSet.Entry;
+import hudson.scm.EditType;
+import hudson.util.ArgumentListBuilder;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import net.sf.json.JSONObject;
+import org.kohsuke.stapler.DataBoundConstructor;
+import org.kohsuke.stapler.StaplerRequest;
+import org.netbeans.api.jackpot.hudson.IndexBuilder;
+
+/**
+ *
+ * @author lahvac
+ */
+public class JackpotIndexBuilder extends IndexBuilder {
+
+    private JackpotIndexBuilder(StaplerRequest req, JSONObject formData) {
+    }
+
+    @DataBoundConstructor
+    public JackpotIndexBuilder() {}
+
+    @Override
+    public boolean index(File cacheDir, AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
+        listener.getLogger().println("Jackpot 3.0 indexing:");
+
+        Set<String> addedFiles = new HashSet<String>();
+        Set<String> removedFiles = new HashSet<String>();
+
+        for (Entry e : build.getChangeSet()) {
+            for (AffectedFile f : e.getAffectedFiles()) {
+                if (f.getEditType() == EditType.DELETE) {
+                    removedFiles.add(f.getPath());
+                } else {
+                    addedFiles.add(f.getPath());
+                }
+            }
+        }
+
+        File a = File.createTempFile("jck30", "");
+        File r = File.createTempFile("jck30", "");
+
+        dumpToFile(a, addedFiles);
+        dumpToFile(r, removedFiles);
+
+        ArgumentListBuilder args = new ArgumentListBuilder();
+
+        args.add("java"); //XXX
+        args.add("-Xbootclasspath/p:" + indexerLocation.getAbsolutePath() + "/lib/javac-api-nb-7.0-b07.jar");
+        args.add("-jar");
+        args.add(new File(indexerLocation, "indexer.jar").getAbsolutePath());
+        args.add("-store-sources");
+        args.add(".");
+        args.add(cacheDir);
+        args.add(a.getAbsolutePath());
+        args.add(r.getAbsolutePath());
+
+        Proc indexer = launcher.launch().pwd(build.getWorkspace())
+                                        .cmds(args)
+                                        .stdout(listener)
+                                        .start();
+
+        indexer.join();
+
+        a.delete();
+        r.delete();
+
+        return true;
+    }
+
+    private void dumpToFile(File target, Set<String> files) throws IOException {
+        Writer out = new OutputStreamWriter(new FileOutputStream(target));
+
+        try {
+            for (String f : files) {
+                out.write(f);
+                out.write("\n");
+            }
+        } finally {
+            out.close();
+        }
+    }
+
+    @Extension // this marker indicates Hudson that this is an implementation of an extension point.
+    public static final class DescriptorImpl extends IndexBuilderDescriptor {
+
+        @Override
+        public JackpotIndexBuilder newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+            return new JackpotIndexBuilder(req, formData);
+        }
+
+        @Override
+        public String getDisplayName() {
+            return "Jackpot 3.0 Indexing";
+        }
+
+    }
+
+
+    private static final File indexerLocation;
+
+    private static final String[] locationsToTest = new String[] {
+        "../../data/compiler/indexer",
+        "../../compiler/indexer",
+    };
+
+    private static File computeIndexerLocation() {
+        URL loc = IndexingBuilder.class.getProtectionDomain().getCodeSource().getLocation();
+        File base;
+        if ("jar".equals(loc.getProtocol())) { //NOI18N
+            String path = loc.getPath();
+            int index = path.indexOf("!/"); //NOI18N
+
+            if (index >= 0) {
+                try {
+                    String jarPath = path.substring(0, index);
+                    if (jarPath.indexOf("file://") > -1 && jarPath.indexOf("file:////") == -1) {  //NOI18N
+                        /* Replace because JDK application classloader wrongly recognizes UNC paths. */
+                        jarPath = jarPath.replaceFirst("file://", "file:////");  //NOI18N
+                    }
+                    loc = new URL(jarPath);
+                } catch (MalformedURLException mue) {
+                    throw new IllegalStateException(mue);
+                }
+            }
+        }
+        if ("file".equals(loc.getProtocol())) {
+            base = new File(loc.getPath());
+        } else {
+            throw new IllegalStateException(loc.toExternalForm());
+        }
+
+        File locFile = null;
+
+        for (String t : locationsToTest) {
+            if (new File(new File(base, t), "indexer.jar").canRead()) {
+                try {
+                    locFile = new File(base, t).getCanonicalFile();
+                } catch (IOException ex) {
+                    //XXX: log
+                    locFile = new File(base, t).getAbsoluteFile();
+                }
+                break;
+            }
+        }
+
+        if (locFile == null) {
+            throw new IllegalStateException(base.getAbsolutePath());
+        }
+
+        return locFile;
+    }
+
+    static {
+        indexerLocation = computeIndexerLocation();
+    }
+}

File server/hudson/src/main/resources/org/netbeans/modules/jackpot30/hudson/IndexingBuilder/config.jelly

View file
+<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
+
+    <f:entry title="Project Name:" field="projectName">
+        <f:textbox />
+    </f:entry>
+
+    <j:forEach var="indexerDescription" items="${descriptor.getIndexers()}" varStatus="loop">
+        <f:optionalBlock name="${indexerDescription.getJsonSafeClassName()}"
+                         title="${indexerDescription.getDisplayName()}"
+                         checked="${instance != null ? instance.isIndexerEnabled(indexerDescription.getJsonSafeClassName()) : false}"
+                         help="${indexerDescription.getHelpFile()}">
+            <st:include from="${indexerDescription}" page="${indexerDescription.configPage}" />
+        </f:optionalBlock>
+    </j:forEach>
+
+</j:jelly>

File server/hudson/src/main/resources/org/netbeans/modules/jackpot30/hudson/IndexingBuilder/global.jelly

View file
+<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
+
+    <f:section title="Indexers">
+        <f:entry title="Cache directory:" field="cacheDir">
+            <f:textbox />
+        </f:entry>
+    </f:section>
+    
+</j:jelly>

File server/hudson/src/main/resources/org/netbeans/modules/jackpot30/hudson/IndexingBuilder/help-cacheDir.html

View file
+<div>
+    Target cache directory.
+</div>

File server/hudson/src/main/resources/org/netbeans/modules/jackpot30/hudson/IndexingBuilder/help.html

View file
+<div>
+    Run indexers.
+</div>

File server/hudson/src/main/resources/org/netbeans/modules/jackpot30/hudson/JackpotIndexBuilder/config.jelly

View file
+<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
+
+</j:jelly>

File server/hudson/src/main/resources/org/netbeans/modules/jackpot30/hudson/JackpotIndexBuilder/help.html

View file
+<div>
+    Run Jackpot 3.0 indexer.
+</div>

File server/indexer/build.xml

View file
     nbproject/build-impl.xml file. 
 
     -->
+
+    <target name="copy-to-hudson" depends="jar">
+        <mkdir dir="${hudson.compiler.dir}" /> <!--only to be sure, should exist-->
+        <copy todir="${hudson.compiler.dir}/indexer">
+            <fileset dir="${dist.dir}"/>
+        </copy>
+    </target>
+
+    <target name="-post-clean">
+        <delete dir="${hudson.compiler.dir}/indexer"/>
+    </target>
 </project>

File server/indexer/nbproject/project.properties

View file
 source.encoding=UTF-8
 src.dir=src
 test.src.dir=test
+
+hudson.compiler.dir=../hudson/data/compiler