Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FIXED JENKINS-753] Allows performing a clean checkout if update fails
[FIXED JENKINS-12595] CVS gets passed the module name so creates lock
files in the correct directory on the remote server
[FIXED JENKINS-12581] CVS plugin now forces a module name in the udpate
command to prevent an attempt to checkout all remote modules
  • Loading branch information
mc1arke committed Feb 5, 2012
1 parent 39da798 commit 794afd7
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 56 deletions.
159 changes: 103 additions & 56 deletions src/main/java/hudson/scm/CVSSCM.java
Expand Up @@ -126,6 +126,8 @@ public class CVSSCM extends SCM implements Serializable {
private boolean pruneEmptyDirectories;

private boolean disableCvsQuiet;

private boolean cleanOnFailedUpdate;

// start legacy fields
@Deprecated
Expand Down Expand Up @@ -153,19 +155,21 @@ public CVSSCM(final String cvsRoot, final String allModules, final String branch
final boolean canUseUpdate, final boolean useHeadIfNotFound, final boolean legacy,
final boolean isTag, final String excludedRegions) {
this(LegacyConvertor.getInstance().convertLegacyConfigToRepositoryStructure(cvsRoot, allModules, branch, isTag, excludedRegions,
useHeadIfNotFound), canUseUpdate, legacy, null, Boolean.getBoolean(CVSSCM.class.getName() + ".skipChangeLog"), true, false);
useHeadIfNotFound), canUseUpdate, legacy, null, Boolean.getBoolean(CVSSCM.class.getName() + ".skipChangeLog"), true, false, false);
}

@DataBoundConstructor
public CVSSCM(final List<CvsRepository> repositories, final boolean canUseUpdate, final boolean legacy,
final CVSRepositoryBrowser browser, final boolean skipChangeLog, final boolean pruneEmptyDirectories, final boolean disableCvsQuiet) {
final CVSRepositoryBrowser browser, final boolean skipChangeLog, final boolean pruneEmptyDirectories,
final boolean disableCvsQuiet, final boolean cleanOnFailedUpdate) {
this.repositories = repositories.toArray(new CvsRepository[repositories.size()]);
this.canUseUpdate = canUseUpdate;
this.skipChangeLog = skipChangeLog;
flatten = !legacy && this.repositories.length == 1 && this.repositories[0].getModules().length == 1 && "".equals(fixNull(this.repositories[0].getModules()[0].getLocalName()));
repositoryBrowser = browser;
this.pruneEmptyDirectories = pruneEmptyDirectories;
this.disableCvsQuiet = disableCvsQuiet;
this.cleanOnFailedUpdate = cleanOnFailedUpdate;
}


Expand Down Expand Up @@ -645,6 +649,11 @@ public boolean isFlatten() {
public boolean isDisableCvsQuiet() {
return disableCvsQuiet;
}

@Exported
public boolean isCleanOnFailedUpdate() {
return cleanOnFailedUpdate;
}

public boolean isLegacy() {
return !flatten;
Expand Down Expand Up @@ -705,11 +714,7 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher

final FilePath module = workspace.child(cvsModule.getCheckoutName());

final Client cvsClient = getCvsClient(repository, envVars);
final GlobalOptions globalOptions = getGlobalOptions(repository, envVars);

final Command cvsCommand;

boolean updateFailed = false;
boolean update = false;

if (flatten) {
Expand All @@ -721,7 +726,13 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher
update = true;
}
}

final FilePath targetWorkspace = flatten ? workspace.getParent() : workspace;

final String moduleName= flatten ?workspace.getName() : cvsModule.getCheckoutName();


// we're doing an update
if (update) {
// we're doing a CVS update
UpdateCommand updateCommand = new UpdateCommand();
Expand All @@ -748,9 +759,22 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher
updateCommand.setUpdateByRevision(CvsModuleLocationType.HEAD.getName().toUpperCase());
updateCommand.setUpdateByDate(dateStamp);
}

if (!perform(updateCommand, targetWorkspace, listener, repository, moduleName, envVars)) {
updateFailed = true;
}

cvsCommand = updateCommand;
} else {
}


// we're doing a checkout
if (!update || (updateFailed && cleanOnFailedUpdate)) {

if (updateFailed) {
listener.getLogger().println("Update failed. Cleaning workspace and performing full checkout");
workspace.deleteContents();
}

// we're doing a CVS checkout
CheckoutCommand checkoutCommand = new CheckoutCommand();

Expand All @@ -774,58 +798,16 @@ public boolean checkout(final AbstractBuild<?, ?> build, final Launcher launcher
// set directory pruning
checkoutCommand.setPruneDirectories(isPruneEmptyDirectories());

// tell it what to checkout the module as - if we're
// flattening then we ignore any user set name
if (flatten) {
checkoutCommand.setCheckoutDirectory(workspace.getName());
} else {
checkoutCommand.setCheckoutDirectory(cvsModule.getCheckoutName());
}
// set where we're checking out to
checkoutCommand.setCheckoutDirectory(moduleName);

// and specify which module to load
checkoutCommand.setModule(cvsModule.getRemoteName());

cvsCommand = checkoutCommand;

}

listener.getLogger().println("cvs " + cvsCommand.getCVSCommand());

final FilePath targetWorkspace = flatten ? workspace.getParent() : update ? workspace.child(cvsModule
.getCheckoutName()) : workspace;

if (!targetWorkspace.act(new FileCallable<Boolean>() {

private static final long serialVersionUID = -7517978923721181408L;

@Override
public Boolean invoke(final File workspace, final VirtualChannel channel) throws RuntimeException {
cvsClient.setLocalPath(workspace.getAbsolutePath());
final BasicListener basicListener = new BasicListener(listener.getLogger(), listener.getLogger());
cvsClient.getEventManager().addCVSListener(basicListener);

try {
return cvsClient.executeCommand(cvsCommand, globalOptions);
} catch (CommandAbortedException e) {
e.printStackTrace(listener.error("CVS Command aborted: " + e.getMessage()));
return false;
} catch (CommandException e) {
e.printStackTrace(listener.error("CVS Command failed: " + e.getMessage()));
return false;
} catch (AuthenticationException e) {
e.printStackTrace(listener.error("CVS Authentication failed: " + e.getMessage()));
return false;
} finally {
try {
cvsClient.getConnection().close();
} catch(IOException ex) {
listener.error("Could not close client connection: " + ex.getMessage());
}
}
if (!perform(checkoutCommand, workspace, listener, repository, moduleName, envVars)) {
return false;
}
})) {
listener.error("Cvs task failed");
return false;

}

}
Expand Down Expand Up @@ -870,6 +852,71 @@ public Void invoke(final File f, final VirtualChannel channel) throws IOExceptio

return true;
}

/**
* Runs a cvs command in the given workspace.
* @param cvsCommand the command to run (checkout, update etc)
* @param workspace the workspace to run the command in
* @param listener where to log output to
* @param repository the repository to connect to
* @param moduleName the name of the directory within the workspace that will have work performed on it
* @param envVars the environmental variables to expand
* @return true if the action succeeds, false otherwise
* @throws IOException on failure handling files or server actions
* @throws InterruptedException if the user cancels the action
*/
private boolean perform(final Command cvsCommand, final FilePath workspace, final TaskListener listener,
final CvsRepository repository, final String moduleName, final EnvVars envVars) throws IOException, InterruptedException {

final Client cvsClient = getCvsClient(repository, envVars);
final GlobalOptions globalOptions = getGlobalOptions(repository, envVars);


if (!workspace.act(new FileCallable<Boolean>() {

private static final long serialVersionUID = -7517978923721181408L;

@Override
public Boolean invoke(final File workspace, final VirtualChannel channel) throws RuntimeException {


if (cvsCommand instanceof UpdateCommand) {
((UpdateCommand) cvsCommand).setFiles(new File[]{new File(workspace, moduleName)});
}

listener.getLogger().println("cvs " + cvsCommand.getCVSCommand());


cvsClient.setLocalPath(workspace.getAbsolutePath());
final BasicListener basicListener = new BasicListener(listener.getLogger(), listener.getLogger());
cvsClient.getEventManager().addCVSListener(basicListener);

try {
return cvsClient.executeCommand(cvsCommand, globalOptions);
} catch (CommandAbortedException e) {
e.printStackTrace(listener.error("CVS Command aborted: " + e.getMessage()));
return false;
} catch (CommandException e) {
e.printStackTrace(listener.error("CVS Command failed: " + e.getMessage()));
return false;
} catch (AuthenticationException e) {
e.printStackTrace(listener.error("CVS Authentication failed: " + e.getMessage()));
return false;
} finally {
try {
cvsClient.getConnection().close();
} catch(IOException ex) {
listener.error("Could not close client connection: " + ex.getMessage());
}
}
}
})) {
listener.error("Cvs task failed");
return false;
}

return true;
}

private Map<CvsRepository, List<CvsFile>> calculateWorkspaceState(final FilePath workspace) throws IOException,
InterruptedException {
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/hudson/scm/CVSSCM/config.jelly
Expand Up @@ -42,5 +42,8 @@ THE SOFTWARE.
<f:entry title="${%Show all CVS output}" field="disableCvsQuiet">
<f:checkbox />
</f:entry>
<f:entry title="${%Perform clean checkout on failed update}" field="cleanOnFailedUpdate">
<f:checkbox />
</f:entry>
<t:listScmBrowsers name="cvs.browser" />
</j:jelly>

0 comments on commit 794afd7

Please sign in to comment.