Re: multiple module checkout with subversion

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Vladimir Sizikov
Hi Francois,

Ah, funny, I was about to write to the list about the very same
problem - there is no simple way to checkout sources into directories
with specified names.

And it's not only about the problem you've found, there are others -
for example, we have different branches of the same product, just
different versions, and the svn URLS end up with different endings:
PROJECT_1_1 and PROJECT_1_2.

So, in order too start a new hudson builds for PROJECT_1_2 I copy the
task from PROJECT_1_1 and then... it does not work, since there are a
lot of entries with PROJECT_1_1 in it (unit tests, artifacts,
javadocs, fingerprints), so simple act of changing subversion URL from
PROJECT_1_1 to PROECT_1_2 leads to excessive amount of changes in
configurations.

I was holding off this message because I didn't know what to propose
on how to specify a directory name where to check out.

In your proposal you just add it after the URL and use ';' to separate
entries. While quite straightforward, I looks a bit too convoluted for
casual Hudson users (maybe I'm wrong!). It would be good to have such
a way to present/configure this that it would be obvious to new users what to
do rather than to read documentation to figure out how to do what they
want, and in my experience, users don't like reading docs/help.

Thanks,
  --Vladimir

--
Vladimir Sizikov
Sun Microsystems                   [hidden email]

On Sun, Nov 12, 2006 at 10:49:55PM +0100, Francois Fernandes wrote:

> Hi,
>
> hudson is great! this is the first thing I wanted to say in here.
>
> While playing around (well, we're not only playing. Hudson is working in
> a productive environment right now) I found a little weakness in hudson
> regarding multi-module-checkouts form subversion.
> Given the following layout of a svn repository:
>
> svn://<server>/project1/trunk
> svn://<server>/project2/trunk
> svn://<server>/project3/trunk
>
> When checking out those porojects hudson will only create a single trunk
> directory and gets a bit confused.
>
> I've tried to solve this by making hudson able to chechout multiple
> modules by supplying each with a name. The appended SubversionSVM.java
> has been modified to support such a checkout descriptor:
>
>
> svn://.../project1/trunk project1; svn://.../project2/trunk project2;...
>
>
> This will place project1 beeing checked out form trunk into the project1
> directory. Same for project2 and project3.
>
> I hope that someone will find this useful.
>
> Cheers
>
> Francois Fernandes

> package hudson.scm;
>
> import hudson.FilePath;
> import hudson.Launcher;
> import hudson.Proc;
> import hudson.Util;
> import hudson.model.Build;
> import hudson.model.BuildListener;
> import hudson.model.Descriptor;
> import hudson.model.Project;
> import hudson.model.TaskListener;
> import hudson.util.ArgumentListBuilder;
> import hudson.util.FormFieldValidator;
> import org.apache.commons.digester.Digester;
> import org.kohsuke.stapler.StaplerRequest;
> import org.kohsuke.stapler.StaplerResponse;
> import org.xml.sax.SAXException;
>
> import javax.servlet.ServletException;
> import javax.servlet.http.HttpServletRequest;
> import java.io.BufferedOutputStream;
> import java.io.BufferedReader;
> import java.io.ByteArrayInputStream;
> import java.io.ByteArrayOutputStream;
> import java.io.File;
> import java.io.FileInputStream;
> import java.io.FileOutputStream;
> import java.io.FileReader;
> import java.io.IOException;
> import java.io.InputStreamReader;
> import java.io.OutputStream;
> import java.io.PrintStream;
> import java.io.PrintWriter;
> import java.util.ArrayList;
> import java.util.Collection;
> import java.util.HashMap;
> import java.util.Iterator;
> import java.util.List;
> import java.util.Map;
> import java.util.Vector;
> import java.util.Map.Entry;
> import java.util.StringTokenizer;
> import java.util.logging.Level;
> import java.util.logging.Logger;
> import java.util.regex.Matcher;
> import java.util.regex.Pattern;
>
> /**
>  * Subversion.
>  *
>  * Check http://svn.collab.net/repos/svn/trunk/subversion/svn/schema/ for
>  * various output formats.
>  *
>  * @author Kohsuke Kawaguchi
>  */
> public class SubversionSCM extends AbstractCVSFamilySCM {
> private List<ModuleEntry> moduleList;
>     private boolean useUpdate;
>     private String username;
>     private String otherOptions;
>
>     SubversionSCM(String modules, boolean useUpdate, String username,
> String otherOptions) {
> // StringBuilder normalizedModules = new StringBuilder();
>
>     this.moduleList = new Vector<ModuleEntry>();
>    
> if (modules.indexOf(';') >= 0) {
>
> StringTokenizer multiModuleTokenizer = new StringTokenizer(modules, ";");
>
> // fetch the tokens beeing separated by ; to make multi-module checkouts
> // with custom target directories possible
> while (multiModuleTokenizer.hasMoreTokens()) {
> String moduleDef = multiModuleTokenizer.nextToken().trim();
> StringTokenizer moduleSpecifierTokenizer = new StringTokenizer(
> moduleDef);
> int tokens = moduleSpecifierTokenizer.countTokens();
>
> if (tokens != 2)
> addSimpleModuleDefinitions(moduleDef);
> else {
> // we've got a proper definition
> String location = moduleSpecifierTokenizer.nextToken();
> String dir = moduleSpecifierTokenizer.nextToken();
>
> if (location.endsWith("/"))
> location = location.substring(0, location.length() - 1);
>
> this.moduleList.add(new ModuleEntry(location, dir));
> }
> }
> } else {
> addSimpleModuleDefinitions(modules);
> }
>
> // this.modules = normalizedModules.toString();
>         this.useUpdate = useUpdate;
>         this.username = nullify(username);
>         this.otherOptions = nullify(otherOptions);
>     }
>
>     SubversionSCM(Vector<ModuleEntry> mods, boolean useUpdate, String username,
> String otherOptions) {
>    
>     this.moduleList = mods;
>         this.useUpdate = useUpdate;
>         this.username = nullify(username);
>         this.otherOptions = nullify(otherOptions);
>     }
>
>    
>     private void addSimpleModuleDefinitions(String modules) {
>       StringTokenizer tokens = new StringTokenizer(modules);
>       while(tokens.hasMoreTokens()) {
>           String m = tokens.nextToken();
>           if(m.endsWith("/"))
>               // the normalized name is always without the trailing '/'
>               m = m.substring(0,m.length()-1);
>          
>           this.moduleList.add(new ModuleEntry(m, getLastPathComponent(m)));
>      }
>     }
>    
> //    public String getModules() {
> //        return moduleList;
> //    }
>
>     public boolean isUseUpdate() {
>         return useUpdate;
>     }
>
>     public String getUsername() {
>         return username;
>     }
>
>     public String getOtherOptions() {
>         return otherOptions;
>     }
>
>     private Collection<String> getModuleDirNames() {
>         List<String> dirs = new ArrayList<String>();
> //        StringTokenizer tokens = new StringTokenizer(moduleList);
> //        while(tokens.hasMoreTokens()) {
> //            dirs.add(getLastPathComponent(tokens.nextToken()));
> //        }
>        
>         for (Iterator<ModuleEntry> iter = this.moduleList.iterator(); iter.hasNext();) {
> ModuleEntry entry = iter.next();
> dirs.add(entry.getModuleDir());
> }
>        
>         return dirs;
>     }
>
>     private boolean calcChangeLog(Build build, File changelogFile, Launcher launcher, BuildListener listener) throws IOException {
>         if(build.getPreviousBuild()==null) {
>             // nothing to compare against
>             return createEmptyChangeLog(changelogFile, listener, "log");
>         }
>
>         PrintStream logger = listener.getLogger();
>
>         Map<String,Integer> previousRevisions = parseRevisionFile(build.getPreviousBuild());
>         Map<String,Integer> thisRevisions     = parseRevisionFile(build);
>
>         Map env = createEnvVarMap(true);
>
>         for( String module : getModuleDirNames() ) {
>             Integer prevRev = previousRevisions.get(module);
>             if(prevRev==null) {
>                 logger.println("no revision recorded for "+module+" in the previous build");
>                 continue;
>             }
>             Integer thisRev = thisRevisions.get(module);
>             if(thisRev!=null && thisRev.equals(prevRev)) {
>                 logger.println("no change for "+module+" since the previous build");
>                 continue;
>             }
>
>             String cmd = DESCRIPTOR.getSvnExe()+" log -v --xml --non-interactive -r "+(prevRev+1)+":BASE "+module;
>             OutputStream os = new BufferedOutputStream(new FileOutputStream(changelogFile));
>             try {
>                 int r = launcher.launch(cmd,env,os,build.getProject().getWorkspace()).join();
>                 if(r!=0) {
>                     listener.fatalError("revision check failed");
>                     // report the output
>                     FileInputStream log = new FileInputStream(changelogFile);
>                     try {
>                         Util.copyStream(log,listener.getLogger());
>                     } finally {
>                         log.close();
>                     }
>                     return false;
>                 }
>             } finally {
>                 os.close();
>             }
>         }
>
>         return true;
>     }
>
>     /*package*/ static Map<String,Integer> parseRevisionFile(Build build) throws IOException {
>         Map<String,Integer> revisions = new HashMap<String,Integer>(); // module -> revision
>         {// read the revision file of the last build
>             File file = getRevisionFile(build);
>             if(!file.exists())
>                 // nothing to compare against
>                 return revisions;
>
>             BufferedReader br = new BufferedReader(new FileReader(file));
>             String line;
>             while((line=br.readLine())!=null) {
>                 int index = line.indexOf('/');
>                 if(index<0) {
>                     continue;   // invalid line?
>                 }
>                 try {
>                     revisions.put(line.substring(0,index), Integer.parseInt(line.substring(index+1)));
>                 } catch (NumberFormatException e) {
>                     // perhaps a corrupted line. ignore
>                 }
>             }
>         }
>
>         return revisions;
>     }
>
>     public boolean checkout(Build build, Launcher launcher, FilePath workspace, BuildListener listener, File changelogFile) throws IOException {
>         boolean result;
>
>         if(useUpdate && isUpdatable(workspace,listener)) {
>             result = update(launcher,workspace,listener);
>             if(!result)
>                 return false;
>         } else {
>             workspace.deleteContents();
>            
>             for (Iterator<ModuleEntry> iter = this.moduleList.iterator(); iter.hasNext();) {
> ModuleEntry entry = iter.next();
> ArgumentListBuilder cmd = new ArgumentListBuilder();
> cmd.add(DESCRIPTOR.getSvnExe(),"co","-q","--non-interactive");
> if(username!=null)
> cmd.add("--username",username);
> if(otherOptions!=null)
> cmd.add(Util.tokenize(otherOptions));
>
> cmd.add(entry.getSVNLocation())
> .add(entry.getModuleDir());
>
> result = run(launcher,cmd,listener,workspace);
> if(!result)
> return false;
> }
>         }
>
>         // write out the revision file
>         PrintWriter w = new PrintWriter(new FileOutputStream(getRevisionFile(build)));
>         try {
>             Map<String,SvnInfo> revMap = buildRevisionMap(workspace,listener);
>             for (Entry<String,SvnInfo> e : revMap.entrySet()) {
>                 w.println( e.getKey() +'/'+ e.getValue().revision );
>             }
>         } finally {
>             w.close();
>         }
>
>         return calcChangeLog(build, changelogFile, launcher, listener);
>     }
>
>     /**
>      * Output from "svn info" command.
>      */
>     public static class SvnInfo {
>         /** The remote URL of this directory */
>         String url;
>         /** Current workspace revision. */
>         int revision = -1;
>
>         private SvnInfo() {}
>
>         /**
>          * Returns true if this object is fully populated.
>          */
>         public boolean isComplete() {
>             return url!=null && revision!=-1;
>         }
>
>         public void setUrl(String url) {
>             this.url = url;
>         }
>
>         public void setRevision(int revision) {
>             this.revision = revision;
>         }
>
>         /**
>          * Executes "svn info" command and returns the parsed output
>          *
>          * @param subject
>          *      The target to run "svn info". Either local path or remote URL.
>          */
>         public static SvnInfo parse(String subject, Map env, FilePath workspace, TaskListener listener) throws IOException {
>             String cmd = DESCRIPTOR.getSvnExe()+" info --xml "+subject;
>             listener.getLogger().println("$ "+cmd);
>
>             ByteArrayOutputStream baos = new ByteArrayOutputStream();
>
>             int r = new Proc(cmd,env,baos,workspace.getLocal()).join();
>             if(r!=0) {
>                 // failed. to allow user to diagnose the problem, send output to log
>                 listener.getLogger().write(baos.toByteArray());
>                 throw new IOException("svn info failed");
>             }
>
>             SvnInfo info = new SvnInfo();
>
>             Digester digester = new Digester();
>             digester.push(info);
>
>             digester.addBeanPropertySetter("info/entry/url");
>             digester.addSetProperties("info/entry/commit","revision","revision");  // set attributes. in particular @revision
>
>             try {
>                 digester.parse(new ByteArrayInputStream(baos.toByteArray()));
>             } catch (SAXException e) {
>                 // failed. to allow user to diagnose the problem, send output to log
>                 listener.getLogger().write(baos.toByteArray());
>                 e.printStackTrace(listener.fatalError("Failed to parse Subversion output"));
>                 throw new IOException("Unabled to parse svn info output");
>             }
>
>             if(!info.isComplete())
>                 throw new IOException("No revision in the svn info output");
>
>             return info;
>         }
>
>     }
>
>     /**
>      * Checks .svn files in the workspace and finds out revisions of the moduleList
>      * that the workspace has.
>      *
>      * @return
>      *      null if the parsing somehow fails. Otherwise a map from module names to revisions.
>      */
>     private Map<String,SvnInfo> buildRevisionMap(FilePath workspace, TaskListener listener) throws IOException {
>         PrintStream logger = listener.getLogger();
>
>         Map<String/*module name*/,SvnInfo> revisions = new HashMap<String,SvnInfo>();
>
>         Map env = createEnvVarMap(false);
>
>         // invoke the "svn info"
>         for( String module : getModuleDirNames() ) {
>             // parse the output
>             SvnInfo info = SvnInfo.parse(module,env,workspace,listener);
>             revisions.put(module,info);
>             logger.println("Revision:"+info.revision);
>         }
>
>         return revisions;
>     }
>
>     /**
>      * Gets the file that stores the revision.
>      */
>     private static File getRevisionFile(Build build) {
>         return new File(build.getRootDir(),"revision.txt");
>     }
>
>     public boolean update(Launcher launcher, FilePath remoteDir, BuildListener listener) throws IOException {
>         ArgumentListBuilder cmd = new ArgumentListBuilder();
>         cmd.add(DESCRIPTOR.getSvnExe(), "update", "-q", "--non-interactive");
>
>         if(username!=null)
>             cmd.add(" --username ",username);
>         if(otherOptions!=null)
>             cmd.add(Util.tokenize(otherOptions));
>
> for (Iterator<ModuleEntry> iter = this.moduleList.iterator(); iter
> .hasNext();) {
> ModuleEntry entry = (ModuleEntry) iter.next();
> if (!run(launcher, cmd, listener, new FilePath(remoteDir, entry
> .getModuleDir())))
> return false;
> }
>
> // StringTokenizer tokens = new StringTokenizer(moduleList);
> // while(tokens.hasMoreTokens()) {
> // if(!run(launcher,cmd,listener,new
> // FilePath(remoteDir,getLastPathComponent(tokens.nextToken()))))
> // return false;
> // }
> return true;
>     }
>
>     /**
>      * Returns true if we can use "svn update" instead of "svn checkout"
>      */
>     private boolean isUpdatable(FilePath workspace,BuildListener listener) {
>    
>     for (Iterator<ModuleEntry> iter = moduleList.iterator(); iter.hasNext();) {
> ModuleEntry entry =  iter.next();
>
> String url = entry.getSVNLocation();
> String moduleName = entry.getModuleDir();
> File module = workspace.child(moduleName).getLocal();
>             try {
>                 SvnInfo svnInfo = SvnInfo.parse(moduleName, createEnvVarMap(false), workspace, listener);
>                 if(!svnInfo.url.equals(url)) {
>                     listener.getLogger().println("Checking out a fresh workspace because the workspace is not "+url);
>                     return false;
>                 }
>             } catch (IOException e) {
>                 listener.getLogger().println("Checking out a fresh workspace because Hudson failed to detect the current workspace "+module);
>                 e.printStackTrace(listener.error(e.getMessage()));
>                 return false;
>             }
>         }
>         return true;
>    
> //        StringTokenizer tokens = new StringTokenizer(moduleList);
> //        while(tokens.hasMoreTokens()) {
> //            String url = tokens.nextToken();
> //            String moduleName = getLastPathComponent(url);
> //            File module = workspace.child(moduleName).getLocal();
> //
> //            try {
> //                SvnInfo svnInfo = SvnInfo.parse(moduleName, createEnvVarMap(false), workspace, listener);
> //                if(!svnInfo.url.equals(url)) {
> //                    listener.getLogger().println("Checking out a fresh workspace because the workspace is not "+url);
> //                    return false;
> //                }
> //            } catch (IOException e) {
> //                listener.getLogger().println("Checking out a fresh workspace because Hudson failed to detect the current workspace "+module);
> //                e.printStackTrace(listener.error(e.getMessage()));
> //                return false;
> //            }
> //        }
> //        return true;
>     }
>
>     public boolean pollChanges(Project project, Launcher launcher, FilePath workspace, TaskListener listener) throws IOException {
>         // current workspace revision
>         Map<String,SvnInfo> wsRev = buildRevisionMap(workspace,listener);
>
>         Map env = createEnvVarMap(false);
>
>         // check the corresponding remote revision
>         for (SvnInfo localInfo : wsRev.values()) {
>             SvnInfo remoteInfo = SvnInfo.parse(localInfo.url,env,workspace,listener);
>             if(remoteInfo.revision > localInfo.revision)
>                 return true;    // change found
>         }
>
>         return false; // no change
>     }
>
>     public ChangeLogParser createChangeLogParser() {
>         return new SubversionChangeLogParser();
>     }
>
>
>     public DescriptorImpl getDescriptor() {
>         return DESCRIPTOR;
>     }
>
>     public void buildEnvVars(Map env) {
>         // no environment variable
>     }
>
>     public FilePath getModuleRoot(FilePath workspace) {
> //        String s;
> //
> //        // if multiple URLs are specified, pick the first one
> //        int idx = moduleList.indexOf(' ');
> //        if(idx>=0)  s = moduleList.substring(0,idx);
> //        else        s = moduleList;
> //
> //        return workspace.child(getLastPathComponent(s));
>    
>     if (moduleList.size() > 0) {
>     return workspace.child(moduleList.get(0).getModuleDir());
>     } else {
>     // no moduleList specified
>     return workspace;
>     }
>     }
>
>     private String getLastPathComponent(String s) {
>         String[] tokens = s.split("/");
>         return tokens[tokens.length-1]; // return the last token
>     }
>    
>     public String getModules (){
>     StringBuilder b = new StringBuilder();
>     for (Iterator<ModuleEntry> iter = moduleList.iterator(); iter.hasNext();) {
> ModuleEntry entry = iter.next();
> b.append(entry.getSVNLocation()).append( " " ).append(entry.getModuleDir()).append(";");
> }
>     return b.toString();
>     }
>    
>
>     static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
>
>     public static final class DescriptorImpl extends Descriptor<SCM> {
>         DescriptorImpl() {
>             super(SubversionSCM.class);
>         }
>
>         public String getDisplayName() {
>             return "Subversion";
>         }
>
>         public SCM newInstance(StaplerRequest req) {
>             return new SubversionSCM(
>                 req.getParameter("svn_modules"),
>                 req.getParameter("svn_use_update")!=null,
>                 req.getParameter("svn_username"),
>                 req.getParameter("svn_other_options")
>             );
>         }
>
>         public String getSvnExe() {
>             String value = (String)getProperties().get("svn_exe");
>             if(value==null)
>                 value = "svn";
>             return value;
>         }
>
>         public void setSvnExe(String value) {
>             getProperties().put("svn_exe",value);
>             save();
>         }
>
>         public boolean configure( HttpServletRequest req ) {
>             setSvnExe(req.getParameter("svn_exe"));
>             return true;
>         }
>
>         /**
>          * Returns the Subversion version information.
>          *
>          * @return
>          *      null if failed to obtain.
>          */
>         public Version version(Launcher l, String svnExe) {
>             try {
>                 if(svnExe==null || svnExe.equals(""))    svnExe="svn";
>
>                 ByteArrayOutputStream out = new ByteArrayOutputStream();
>                 l.launch(new String[]{svnExe,"--version"},new String[0],out,FilePath.RANDOM).join();
>
>                 // parse the first line for version
>                 BufferedReader r = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(out.toByteArray())));
>                 String line;
>                 while((line = r.readLine())!=null) {
>                     Matcher m = SVN_VERSION.matcher(line);
>                     if(m.matches())
>                         return new Version(Integer.parseInt(m.group(2)), m.group(1));
>                 }
>
>                 // ancient version of subversions didn't have the fixed version number line.
>                 // or maybe something else is going wrong.
>                 LOGGER.log(Level.WARNING, "Failed to parse the first line from svn output: "+line);
>                 return new Version(0,"(unknown)");
>             } catch (IOException e) {
>                 // Stack trace likely to be overkill for a problem that isn't necessarily a problem at all:
>                 LOGGER.log(Level.WARNING, "Failed to check svn version: {0}", e.toString());
>                 return null; // failed to obtain
>             }
>         }
>
>         // web methods
>
>         public void doVersionCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
>             // this method runs a new process, so it needs to be protected
>             new FormFieldValidator(req,rsp,true) {
>                 protected void check() throws IOException, ServletException {
>                     String svnExe = request.getParameter("exe");
>
>                     Version v = version(new Launcher(TaskListener.NULL),svnExe);
>                     if(v==null) {
>                         error("Failed to check subversion version info. Is this a valid path?");
>                         return;
>                     }
>                     if(v.isOK()) {
>                         ok();
>                     } else {
>                         error("Version "+v.versionId+" found, but 1.3.0 is required");
>                     }
>                 }
>             }.process();
>         }
>     }
>
>     public static final class Version {
>         private final int revision;
>         private String versionId;
>
>         public Version(int revision, String versionId) {
>             this.revision = revision;
>             this.versionId = versionId;
>         }
>
>         /**
>          * Repository revision ID of this build.
>          */
>         public int getRevision() {
>             return revision;
>         }
>
>         /**
>          * Human-readable version string.
>          */
>         public String getVersionId() {
>             return versionId;
>         }
>
>         /**
>          * We use "svn info --xml", which is new in 1.3.0
>          */
>         public boolean isOK() {
>             return revision>=17949;
>         }
>     }
>
>     private static final class ModuleEntry {
>     public ModuleEntry(String location, String moduleDir) {
>     this.location = location;
>     this.moduleDir = moduleDir;
> }
> private String location;
>     private String moduleDir;
>    
> public String getSVNLocation() {
> return location;
> }
> public String getModuleDir() {
> return moduleDir;
> }
>    
>    
>     }
>    
>     private static final Pattern SVN_VERSION = Pattern.compile("svn, .+ ([0-9.]+) \\(r([0-9]+)\\)");
>
>     private static final Logger LOGGER = Logger.getLogger(SubversionSCM.class.getName());
> }
>

> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Francois Fernandes
Hi Vladimir,

thank you for your feedback! I completely agree with you that the way I
tried to solve this problem is not straight-forward for hudson users.
There should be a different, more comfortable way to define such module
checkouts. I tried to create a ui definition like when configuring ant
or svn homes in hudson. The problem is that I had some problems getting
this done as most parts of hudson are a mystery to me :-)
So I decided to do it the "simple" way (form the coding sight) as I
needed such a solution to use hudson for our projects.

To your problem regarding the branches PROJECT_1_1 and PROJECT_1_2:
whould it be really such a big problem copy the tasks for these brachnes
if you define the local checkout directories?

example:
http://<snvserver>/<path>/PROJECT_1_1 to directory project

Now when doing the configuration you'll define all junit resources based
on the project directory.
When copying the task the only thing you've got to change ist the
project url:
http://<snvserver>/<path>/PROJECT_1_2 to directory project

All artifacts will be again in the project directory and all paths
you've supplied will be correct.
Maybe I didn't understand your problem. (what happens regularly to me :-) )

cheers

Francois


Vladimir Sizikov schrieb:

> Hi Francois,
>
> Ah, funny, I was about to write to the list about the very same
> problem - there is no simple way to checkout sources into directories
> with specified names.
>
> And it's not only about the problem you've found, there are others -
> for example, we have different branches of the same product, just
> different versions, and the svn URLS end up with different endings:
> PROJECT_1_1 and PROJECT_1_2.
>
> So, in order too start a new hudson builds for PROJECT_1_2 I copy the
> task from PROJECT_1_1 and then... it does not work, since there are a
> lot of entries with PROJECT_1_1 in it (unit tests, artifacts,
> javadocs, fingerprints), so simple act of changing subversion URL from
> PROJECT_1_1 to PROECT_1_2 leads to excessive amount of changes in
> configurations.
>
> I was holding off this message because I didn't know what to propose
> on how to specify a directory name where to check out.
>
> In your proposal you just add it after the URL and use ';' to separate
> entries. While quite straightforward, I looks a bit too convoluted for
> casual Hudson users (maybe I'm wrong!). It would be good to have such
> a way to present/configure this that it would be obvious to new users what to
> do rather than to read documentation to figure out how to do what they
> want, and in my experience, users don't like reading docs/help.
>
> Thanks,
>   --Vladimir
>
> --
> Vladimir Sizikov
> Sun Microsystems                   [hidden email]
>
> On Sun, Nov 12, 2006 at 10:49:55PM +0100, Francois Fernandes wrote:
>> Hi,
>>
>> hudson is great! this is the first thing I wanted to say in here.
>>
>> While playing around (well, we're not only playing. Hudson is working in
>> a productive environment right now) I found a little weakness in hudson
>> regarding multi-module-checkouts form subversion.
>> Given the following layout of a svn repository:
>>
>> svn://<server>/project1/trunk
>> svn://<server>/project2/trunk
>> svn://<server>/project3/trunk
>>
>> When checking out those porojects hudson will only create a single trunk
>> directory and gets a bit confused.
>>
>> I've tried to solve this by making hudson able to chechout multiple
>> modules by supplying each with a name. The appended SubversionSVM.java
>> has been modified to support such a checkout descriptor:
>>
>>
>> svn://.../project1/trunk project1; svn://.../project2/trunk project2;...
>>
>>
>> This will place project1 beeing checked out form trunk into the project1
>> directory. Same for project2 and project3.
>>
>> I hope that someone will find this useful.
>>
>> Cheers
>>
>> Francois Fernandes

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Kohsuke Kawaguchi-2
In reply to this post by Vladimir Sizikov

Thanks for pointing this out. This obviously needs to be fixed, and I agree.

I also agree with Vladimir that we'd probably like to work out a better
UI for specifying multiple source roots. If you could file an issue on
this, that would be great.

Since you've managed to hack Hudson, would you be interested in doing
the rest by yourself :-) ?  I'm also curious what your experience was in
building Hudson. Have you had any issues with that?

Francois Fernandes wrote:

> Hi,
>
> hudson is great! this is the first thing I wanted to say in here.
>
> While playing around (well, we're not only playing. Hudson is working in
> a productive environment right now) I found a little weakness in hudson
> regarding multi-module-checkouts form subversion.
> Given the following layout of a svn repository:
>
> svn://<server>/project1/trunk
> svn://<server>/project2/trunk
> svn://<server>/project3/trunk
>
> When checking out those porojects hudson will only create a single trunk
> directory and gets a bit confused.
>
> I've tried to solve this by making hudson able to chechout multiple
> modules by supplying each with a name. The appended SubversionSVM.java
> has been modified to support such a checkout descriptor:
>
>
> svn://.../project1/trunk project1; svn://.../project2/trunk project2;...
>
>
> This will place project1 beeing checked out form trunk into the project1
> directory. Same for project2 and project3.


--
Kohsuke Kawaguchi
Sun Microsystems                   [hidden email]

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Francois Fernandes
Kohsuke Kawaguchi schrieb:
>
> Thanks for pointing this out. This obviously needs to be fixed, and I
> agree.
>
> I also agree with Vladimir that we'd probably like to work out a better
> UI for specifying multiple source roots. If you could file an issue on
> this, that would be great.

I'll file an issue and add an comment that I'm working on it.

> Since you've managed to hack Hudson, would you be interested in doing
> the rest by yourself :-) ?  I'm also curious what your experience was in
> building Hudson. Have you had any issues with that?

I'll try to do the coding for checking out multiple modules form
subversion. The basic technology of hudson is very interesting and I
really like challenges! :-)
Regarding building hudson I've got to say that I used the version before
the migration to maven (ok, I know this is not really the cool way :-)
). I'll try to migrate that code to the current hudson sources and do
some UI beautifying. The basic idea I've got right now is to use the
same mechanism like the configuration of ant and svn homes in the
managing hudson section. Would that be ok?

> Francois Fernandes wrote:
>> Hi,
>>
>> hudson is great! this is the first thing I wanted to say in here.
>>
>> While playing around (well, we're not only playing. Hudson is working in
>> a productive environment right now) I found a little weakness in hudson
>> regarding multi-module-checkouts form subversion.
>> Given the following layout of a svn repository:
>>
>> svn://<server>/project1/trunk
>> svn://<server>/project2/trunk
>> svn://<server>/project3/trunk
>>
>> When checking out those porojects hudson will only create a single trunk
>> directory and gets a bit confused.
>>
>> I've tried to solve this by making hudson able to chechout multiple
>> modules by supplying each with a name. The appended SubversionSVM.java
>> has been modified to support such a checkout descriptor:
>>
>>
>> svn://.../project1/trunk project1; svn://.../project2/trunk project2;...
>>
>>
>> This will place project1 beeing checked out form trunk into the project1
>> directory. Same for project2 and project3.
>
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Vladimir Sizikov
Hi,

On Mon, Nov 13, 2006 at 07:30:07PM +0100, Francois Fernandes wrote:
> ). I'll try to migrate that code to the current hudson sources and do
> some UI beautifying. The basic idea I've got right now is to use the
> same mechanism like the configuration of ant and svn homes in the
> managing hudson section. Would that be ok?

I'm not Kohsuke, but for me it sounds good, clean, consistent and
simple enough. :)

Thanks,
  --Vladimir

--
Vladimir Sizikov
Sun Microsystems                   [hidden email]

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Kohsuke Kawaguchi-2
In reply to this post by Francois Fernandes
Francois Fernandes wrote:
> I'll try to do the coding for checking out multiple modules form
> subversion. The basic technology of hudson is very interesting and I
> really like challenges! :-)

Cool.

> Regarding building hudson I've got to say that I used the version before
> the migration to maven (ok, I know this is not really the cool way :-)
> ). I'll try to migrate that code to the current hudson sources and do
> some UI beautifying. The basic idea I've got right now is to use the
> same mechanism like the configuration of ant and svn homes in the
> managing hudson section. Would that be ok?

That would be excellent.

--
Kohsuke Kawaguchi
Sun Microsystems                   [hidden email]

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Kohsuke Kawaguchi-2
In reply to this post by Francois Fernandes
Francois Fernandes wrote:

> Kohsuke Kawaguchi schrieb:
>>
>> Thanks for pointing this out. This obviously needs to be fixed, and I
>> agree.
>>
>> I also agree with Vladimir that we'd probably like to work out a better
>> UI for specifying multiple source roots. If you could file an issue on
>> this, that would be great.
>
> I'll file an issue and add an comment that I'm working on it.
>
>> Since you've managed to hack Hudson, would you be interested in doing
>> the rest by yourself :-) ?  I'm also curious what your experience was in
>> building Hudson. Have you had any issues with that?
>
> I'll try to do the coding for checking out multiple modules form
> subversion. The basic technology of hudson is very interesting and I
> really like challenges! :-)
> Regarding building hudson I've got to say that I used the version before
> the migration to maven (ok, I know this is not really the cool way :-)
> ). I'll try to migrate that code to the current hudson sources and do
> some UI beautifying. The basic idea I've got right now is to use the
> same mechanism like the configuration of ant and svn homes in the
> managing hudson section. Would that be ok?
Hi, how is this going?

Feel free to let us know if you need any help...



--
Kohsuke Kawaguchi
Sun Microsystems                   [hidden email]

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: multiple module checkout with subversion

Francois Fernandes
Bug #153 has been updated and a patch is attached to it.


Kohsuke Kawaguchi schrieb:

> Francois Fernandes wrote:
>> Kohsuke Kawaguchi schrieb:
>>>
>>> Thanks for pointing this out. This obviously needs to be fixed, and I
>>> agree.
>>>
>>> I also agree with Vladimir that we'd probably like to work out a
>>> better UI for specifying multiple source roots. If you could file an
>>> issue on this, that would be great.
>>
>> I'll file an issue and add an comment that I'm working on it.
>>
>>> Since you've managed to hack Hudson, would you be interested in doing
>>> the rest by yourself :-) ?  I'm also curious what your experience was
>>> in building Hudson. Have you had any issues with that?
>>
>> I'll try to do the coding for checking out multiple modules form
>> subversion. The basic technology of hudson is very interesting and I
>> really like challenges! :-)
>> Regarding building hudson I've got to say that I used the version
>> before the migration to maven (ok, I know this is not really the cool
>> way :-) ). I'll try to migrate that code to the current hudson sources
>> and do some UI beautifying. The basic idea I've got right now is to
>> use the same mechanism like the configuration of ant and svn homes in
>> the managing hudson section. Would that be ok?
>
> Hi, how is this going?
>
> Feel free to let us know if you need any help...
>
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]