You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2018/06/04 09:38:58 UTC

[maven-wagon] branch wagon-scm-git updated (7aff221 -> 2e70c85)

This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a change to branch wagon-scm-git
in repository https://gitbox.apache.org/repos/asf/maven-wagon.git.


 discard 7aff221  [WAGON-495] Fix checkoutDirectory leak
 discard 8f91f4c  [WAGON-497] ScmWagon#put() strips parent dirs from the target path if they already exist in SCM
 discard ca60e84  [WAGON-501] Add ScmGitExeWagonTest
     new 7ac6a74  [WAGON-501] Add ScmGitExeWagonTest
     new 66ce798  [WAGON-497] ScmWagon#put() strips parent dirs from the target path if they already exist in SCM
     new 2e70c85  [WAGON-495] Fix checkoutDirectory leak

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (7aff221)
            \
             N -- N -- N   refs/heads/wagon-scm-git (2e70c85)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../wagon-scm/src/test/resources/test-repo-git/.gitattributes    | 9 +++------
 wagon-providers/wagon-scm/src/test/resources/test-repo-git/HEAD  | 2 +-
 .../wagon-scm/src/test/resources/test-repo-git/refs/heads/master | 2 +-
 3 files changed, 5 insertions(+), 8 deletions(-)

-- 
To stop receiving notification emails like this one, please contact
michaelo@apache.org.

[maven-wagon] 01/03: [WAGON-501] Add ScmGitExeWagonTest

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch wagon-scm-git
in repository https://gitbox.apache.org/repos/asf/maven-wagon.git

commit 7ac6a74d9afa9dca621b0adf38b636b3316129f7
Author: Ilya Basin <ba...@gmail.com>
AuthorDate: Wed Feb 21 11:52:26 2018 +0300

    [WAGON-501] Add ScmGitExeWagonTest
    
    This closes #45
---
 wagon-providers/wagon-scm/pom.xml                  |   6 ++
 .../providers/scm/AbstractScmGitWagonTest.java     |  66 ++++++++++++++++++
 .../wagon/providers/scm/ScmGitExeWagonTest.java    |  75 +++++++++++++++++++++
 .../test/resources/test-repo-git/.gitattributes    |   3 +
 .../src/test/resources/test-repo-git/HEAD          |   1 +
 .../src/test/resources/test-repo-git/config        |   8 +++
 .../src/test/resources/test-repo-git/description   |   1 +
 .../src/test/resources/test-repo-git/info/exclude  |   6 ++
 .../resources/test-repo-git/objects/.gitignore     |   0
 .../3a/67db9b159d7130f6fb7bf6588f9c2619fecafe      | Bin 0 -> 185 bytes
 .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391      | Bin 0 -> 18 bytes
 .../eb/e0326d9241016f3133fdf9672970ca178c640c      | Bin 0 -> 52 bytes
 .../test/resources/test-repo-git/refs/.gitignore   |   0
 .../test/resources/test-repo-git/refs/heads/master |   1 +
 14 files changed, 167 insertions(+)

diff --git a/wagon-providers/wagon-scm/pom.xml b/wagon-providers/wagon-scm/pom.xml
index 08894e0..ee41116 100644
--- a/wagon-providers/wagon-scm/pom.xml
+++ b/wagon-providers/wagon-scm/pom.xml
@@ -61,6 +61,12 @@ under the License.
     </dependency>
     <dependency>
       <groupId>org.apache.maven.scm</groupId>
+      <artifactId>maven-scm-provider-gitexe</artifactId>
+      <version>${mavenScmVersion}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.scm</groupId>
       <artifactId>maven-scm-provider-svnexe</artifactId>
       <version>${mavenScmVersion}</version>
       <scope>test</scope>
diff --git a/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/AbstractScmGitWagonTest.java b/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/AbstractScmGitWagonTest.java
new file mode 100644
index 0000000..707273c
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/AbstractScmGitWagonTest.java
@@ -0,0 +1,66 @@
+package org.apache.maven.wagon.providers.scm;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+
+import org.codehaus.plexus.util.FileUtils;
+
+/**
+ * Test for ScmWagon using Git as underlying SCM
+ */
+public abstract class AbstractScmGitWagonTest
+    extends AbstractScmWagonTest
+{
+    private String repository;
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        // copy the repo for the test
+
+        File origRepo = getTestFile( "target/test-classes/test-repo-git" );
+
+        File testRepo = getTestFile( "target/test-classes/test-repo-git-test" );
+
+        FileUtils.deleteDirectory( testRepo );
+
+        FileUtils.copyDirectoryStructure( origRepo, testRepo );
+
+        repository = "scm:git:" + testRepo.toPath().toUri();
+    }
+
+    protected String getScmId()
+    {
+        return "git";
+    }
+
+    protected String getTestRepositoryUrl()
+    {
+        return repository;
+    }
+
+    protected boolean supportsGetIfNewer()
+    {
+        return false;
+    }
+}
diff --git a/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/ScmGitExeWagonTest.java b/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/ScmGitExeWagonTest.java
new file mode 100644
index 0000000..2cb2d84
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/ScmGitExeWagonTest.java
@@ -0,0 +1,75 @@
+package org.apache.maven.wagon.providers.scm;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.provider.git.gitexe.GitExeScmProvider;
+
+/**
+ * Test for ScmWagon using Git Exe as underlying SCM
+ */
+public class ScmGitExeWagonTest
+    extends AbstractScmGitWagonTest
+{
+
+    protected ScmProvider getScmProvider()
+    {
+        return new GitExeScmProvider();
+    }
+
+    @Override
+    public void testWagonGetFileList()
+        throws Exception
+    {
+        // remote list unsupported
+        // When a command is unsupported, SCM throws NoSuchCommandScmException.
+        // However, there's no equivalent exception in the Wagon API.
+        // ScmWagon wraps NoSuchCommandScmException with TransferFailedException, which gives no specific info.
+        // TODO: WagonTestCase should somehow determine whether a command was unsupported
+        // and skip the test using org.junit.Assume
+    }
+
+    @Override
+    public void testWagonGetFileListWhenDirectoryDoesNotExist()
+        throws Exception
+    {
+        // remote list unsupported
+    }
+
+    @Override
+    public void testWagonResourceExists()
+        throws Exception
+    {
+        // remote list unsupported
+    }
+
+    @Override
+    public void testWagonResourceNotExists()
+        throws Exception
+    {
+        // remote list unsupported
+    }
+
+    @Override
+    protected boolean supportsGetIfNewer()
+    {
+        return false;
+    }
+}
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/.gitattributes b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/.gitattributes
new file mode 100644
index 0000000..5e0feff
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/.gitattributes
@@ -0,0 +1,3 @@
+objects/** binary
+* text eol=lf
+
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/HEAD b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/HEAD
new file mode 100644
index 0000000..cb089cd
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/config b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/config
new file mode 100644
index 0000000..ad4d134
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/config
@@ -0,0 +1,8 @@
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = true
+	ignorecase = false
+	compression = 0
+[gc]
+	auto = 0
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/description b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/description
new file mode 100644
index 0000000..498b267
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/info/exclude b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/info/exclude
new file mode 100644
index 0000000..a5196d1
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/.gitignore b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/3a/67db9b159d7130f6fb7bf6588f9c2619fecafe b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/3a/67db9b159d7130f6fb7bf6588f9c2619fecafe
new file mode 100644
index 0000000..48201e6
Binary files /dev/null and b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/3a/67db9b159d7130f6fb7bf6588f9c2619fecafe differ
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644
index 0000000..0b464ce
Binary files /dev/null and b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 differ
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/eb/e0326d9241016f3133fdf9672970ca178c640c b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/eb/e0326d9241016f3133fdf9672970ca178c640c
new file mode 100644
index 0000000..6859511
Binary files /dev/null and b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/objects/eb/e0326d9241016f3133fdf9672970ca178c640c differ
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/refs/.gitignore b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/refs/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/wagon-providers/wagon-scm/src/test/resources/test-repo-git/refs/heads/master b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/refs/heads/master
new file mode 100644
index 0000000..5e55c50
--- /dev/null
+++ b/wagon-providers/wagon-scm/src/test/resources/test-repo-git/refs/heads/master
@@ -0,0 +1 @@
+3a67db9b159d7130f6fb7bf6588f9c2619fecafe

-- 
To stop receiving notification emails like this one, please contact
michaelo@apache.org.

[maven-wagon] 03/03: [WAGON-495] Fix checkoutDirectory leak

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch wagon-scm-git
in repository https://gitbox.apache.org/repos/asf/maven-wagon.git

commit 2e70c858b7031b105951ee33252410590ae5e785
Author: Ilya Basin <ba...@gmail.com>
AuthorDate: Thu Feb 22 11:13:52 2018 +0300

    [WAGON-495] Fix checkoutDirectory leak
    
    This closes #46
---
 .../apache/maven/wagon/providers/scm/ScmWagon.java | 248 ++++++++++++---------
 1 file changed, 139 insertions(+), 109 deletions(-)

diff --git a/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java b/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java
index 09b014d..d6531ee 100644
--- a/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java
+++ b/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java
@@ -19,6 +19,13 @@ package org.apache.maven.wagon.providers.scm;
  * under the License.
  */
 
+import java.io.File;
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
 import org.apache.maven.scm.CommandParameter;
 import org.apache.maven.scm.CommandParameters;
 import org.apache.maven.scm.ScmBranch;
@@ -32,6 +39,7 @@ import org.apache.maven.scm.ScmVersion;
 import org.apache.maven.scm.command.add.AddScmResult;
 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
 import org.apache.maven.scm.command.list.ListScmResult;
+import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.manager.NoSuchScmProviderException;
 import org.apache.maven.scm.manager.ScmManager;
 import org.apache.maven.scm.provider.ScmProvider;
@@ -49,14 +57,6 @@ import org.apache.maven.wagon.resource.Resource;
 import org.codehaus.plexus.util.FileUtils;
 import org.codehaus.plexus.util.StringUtils;
 
-import java.io.File;
-import java.io.IOException;
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.Stack;
-
 /**
  * Wagon provider to get and put files from and to SCM systems, using Maven-SCM as underlying transport.
  * <p/>
@@ -95,6 +95,11 @@ public class ScmWagon
      */
     private String scmVersionType;
 
+    /**
+     * Empty string or subdir ending with slash.
+     */
+    private String partCOSubdir = "";
+
     private File checkoutDirectory;
 
     /**
@@ -371,18 +376,19 @@ public class ScmWagon
 
             ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() );
 
-            String checkoutTargetName = source.isDirectory() ? targetName : getDirname( targetName );
-            String relPath = checkOut( scmProvider, scmRepository, checkoutTargetName, target );
+            boolean isDirectory = source.isDirectory();
+            String checkoutTargetName = isDirectory ? targetName : getDirname( targetName );
+            String relPath = ensureDirs( scmProvider, scmRepository, checkoutTargetName, target );
 
             File newCheckoutDirectory = new File( checkoutDirectory, relPath );
 
-            File scmFile = new File( newCheckoutDirectory, source.isDirectory() ? "" : getFilename( targetName ) );
+            File scmFile = new File( newCheckoutDirectory, isDirectory ? "" : FileUtils.removePath( targetName, '/' ) );
 
             boolean fileAlreadyInScm = scmFile.exists();
 
             if ( !scmFile.equals( source ) )
             {
-                if ( source.isDirectory() )
+                if ( isDirectory )
                 {
                     FileUtils.copyDirectoryStructure( source, scmFile );
                 }
@@ -395,7 +401,7 @@ public class ScmWagon
             if ( !fileAlreadyInScm || scmFile.isDirectory() )
             {
                 int addedFiles = addFiles( scmProvider, scmRepository, newCheckoutDirectory,
-                                           source.isDirectory() ? "" : scmFile.getName() );
+                                           isDirectory ? "" : scmFile.getName() );
 
                 if ( !fileAlreadyInScm && addedFiles == 0 )
                 {
@@ -439,14 +445,16 @@ public class ScmWagon
      * @param targetName
      * @return
      * @throws TransferFailedException
+     * @throws IOException
      */
-    private String checkOut( ScmProvider scmProvider, ScmRepository scmRepository, String targetName,
+    private String ensureDirs( ScmProvider scmProvider, ScmRepository scmRepository, String targetName,
                              Resource resource )
-        throws TransferFailedException
+        throws TransferFailedException, IOException
     {
-        checkoutDirectory = createCheckoutDirectory();
-
-        Stack<String> stack = new Stack<String>();
+        if ( checkoutDirectory == null )
+        {
+            checkoutDirectory = createCheckoutDirectory();
+        }
 
         String target = targetName;
 
@@ -455,87 +463,82 @@ public class ScmWagon
         // Check whether targetName, which is a relative path into the scm, exists.
         // If it doesn't, check the parent, etc.
 
-        try
+        for ( ;; )
         {
-            while ( target.length() > 0 && !scmProvider.list( scmRepository,
-                                                              new ScmFileSet( new File( "." ), new File( target ) ),
-                                                              false, makeScmVersion() ).isSuccess() )
+            try
+            {
+                ScmResult res = tryPartialCheckout( target );
+                if ( !res.isSuccess() )
+                {
+                    throw new ScmException( "command failed: " + res.getCommandOutput().trim() );
+                }
+                break;
+            }
+            catch ( ScmException e )
             {
-                stack.push( getFilename( target ) );
+                if ( partCOSubdir.length() == 0 )
+                {
+                    fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+
+                    throw new TransferFailedException( "Error checking out: " + e.getMessage(), e );
+                }
                 target = getDirname( target );
             }
         }
-        catch ( ScmException e )
-        {
-            fireTransferError( resource, e, TransferEvent.REQUEST_GET );
 
-            throw new TransferFailedException( "Error listing repository: " + e.getMessage(), e );
-        }
+        // now create the subdirs in target, if it's a parent of targetName
+
+        String res =
+            partCOSubdir.length() >= targetName.length() ? "" : targetName.substring( partCOSubdir.length() ) + '/';
 
-        // ok, we've established that target exists, or is empty.
-        // Check the resource out; if it doesn't exist, that means we're in the svn repo url root,
-        // and the configuration is incorrect. We will not try repo.getParent since most scm's don't
-        // implement that.
+        ArrayList<File> createdDirs = new ArrayList<File>();
+        File deepDir = new File( checkoutDirectory, res );
 
-        target = target.replace( '\\', '/' );
+        boolean added = false;
         try
         {
-            String repoUrl = getRepository().getUrl();
-            if ( "svn".equals( scmProvider.getScmType() ) )
+            mkdirsThrow( deepDir, createdDirs );
+            if ( createdDirs.size() != 0 )
             {
-                // Subversion is the only SCM that adds path structure to represent tags and branches.
-                // The rest use scmVersion and scmVersionType.
-                if ( target.length() > 0 )
-                {
-                    repoUrl += "/" + target;
-                    target = "";
-                }
-            }
-            scmRepository = getScmRepository( repoUrl );
-
-            CheckOutScmResult ret =
-                checkOut( scmProvider, scmRepository, new ScmFileSet( new File( checkoutDirectory, "" ) ) );
+                File topNewDir = createdDirs.get( 0 );
+                String relTopNewDir =
+                    topNewDir.getPath().substring( checkoutDirectory.getPath().length() + 1 ).replace( '\\', '/' );
 
-            checkScmResult( ret );
+                addFiles( scmProvider, scmRepository, checkoutDirectory, relTopNewDir );
+                added = true;
+            }
         }
         catch ( ScmException e )
         {
-            fireTransferError( resource, e, TransferEvent.REQUEST_GET );
+            fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
 
-            throw new TransferFailedException( "Error checking out: " + e.getMessage(), e );
+            throw new TransferFailedException( "Failed to add directory " + createdDirs.get( 0 ) + " to working copy",
+                                               e );
         }
-
-        // now create the subdirs in target, if it's a parent of targetName
-
-        String relPath = target.concat( target.length() > 0 ? "/" : "" );
-
-        while ( !stack.isEmpty() )
+        finally
         {
-            String p = stack.pop();
-            relPath += p + "/";
-
-            File newDir = new File( checkoutDirectory, relPath );
-            newDir.mkdir();
-            if ( !newDir.isDirectory() )
+            if ( !added && createdDirs.size() != 0 )
             {
-                throw new TransferFailedException(
-                    "Failed to create directory " + newDir.getAbsolutePath() + "; parent should exist: "
-                        + checkoutDirectory );
+                FileUtils.deleteDirectory( createdDirs.get( 0 ) );
             }
+        }
 
-            try
-            {
-                addFiles( scmProvider, scmRepository, checkoutDirectory, relPath );
-            }
-            catch ( ScmException e )
-            {
-                fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
+        return res;
+    }
 
-                throw new TransferFailedException( "Failed to add directory " + newDir + " to working copy", e );
+    private static void mkdirsThrow( File f, List<File> createdDirs )
+        throws IOException
+    {
+        if ( !f.isDirectory() )
+        {
+            File parent = f.getParentFile();
+            mkdirsThrow( parent, createdDirs );
+            if ( !f.mkdir() )
+            {
+                throw new IOException( "Failed to create directory " + f.getAbsolutePath() );
             }
+            createdDirs.add( f );
         }
-
-        return relPath;
     }
 
     /**
@@ -623,6 +626,12 @@ public class ScmWagon
         return true;
     }
 
+    private boolean supportsPartialCheckout( ScmProvider scmProvider )
+    {
+        String scmType = scmProvider.getScmType();
+        return ( "svn".equals( scmType ) || "cvs".equals( scmType ) );
+    }
+
     public void putDirectory( File sourceDirectory, String destinationDirectory )
         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
     {
@@ -677,16 +686,19 @@ public class ScmWagon
 
         fireGetInitiated( resource, destination );
 
-        String url = getRepository().getUrl() + "/" + resourceName;
-
-        // remove the file
-        url = url.substring( 0, url.lastIndexOf( '/' ) );
+        fireGetStarted( resource, destination );
 
         try
         {
-            ScmRepository scmRepository = getScmRepository( url );
-
-            fireGetStarted( resource, destination );
+            String subdir = getDirname( resourceName );
+            ScmResult res = tryPartialCheckout( subdir );
+            if ( !res.isSuccess() && ( partCOSubdir.length() == 0 || res instanceof UpdateScmResult ) )
+            {
+                // inability to checkout SVN or CVS subdir is not fatal. We just assume it doesn't exist
+                // inability to update existing subdir or checkout root is fatal
+                throw new ScmException( "command failed: " + res.getCommandOutput().trim() );
+            }
+            resourceName = resourceName.substring( partCOSubdir.length() );
 
             // TODO: limitations:
             // - destination filename must match that in the repository - should allow the "-d" CVS equiv to be passed
@@ -697,24 +709,6 @@ public class ScmWagon
 
             File scmFile = new File( checkoutDirectory, resourceName );
 
-            File basedir = scmFile.getParentFile();
-
-            ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() );
-
-            String reservedScmFile = scmProvider.getScmSpecificFilename();
-
-            if ( reservedScmFile != null && new File( basedir, reservedScmFile ).exists() )
-            {
-                scmProvider.update( scmRepository, new ScmFileSet( basedir ), makeScmVersion() );
-            }
-            else
-            {
-                // TODO: this should be checking out a full hierarchy (requires the -d equiv)
-                basedir.mkdirs();
-
-                checkOut( scmProvider, scmRepository, new ScmFileSet( basedir ) );
-            }
-
             if ( !scmFile.exists() )
             {
                 throw new ResourceDoesNotExistException( "Unable to find resource " + destination + " after checkout" );
@@ -743,6 +737,49 @@ public class ScmWagon
         fireGetCompleted( resource, destination );
     }
 
+    private ScmResult tryPartialCheckout( String subdir )
+        throws ScmException, IOException
+    {
+        String url = getRepository().getUrl();
+
+        String desiredPartCOSubdir = "";
+
+        ScmRepository scmRepository = getScmRepository( url );
+        ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() );
+        if ( subdir.length() != 0 && supportsPartialCheckout( scmProvider ) )
+        {
+            url += ( url.endsWith( "/" ) ? "" : "/" ) + subdir;
+
+            desiredPartCOSubdir = subdir + "/";
+
+            scmRepository = getScmRepository( url );
+        }
+
+        if ( !desiredPartCOSubdir.equals( partCOSubdir ) )
+        {
+            FileUtils.deleteDirectory( checkoutDirectory );
+            partCOSubdir = desiredPartCOSubdir;
+        }
+
+        ScmResult res;
+        if ( checkoutDirExists( scmProvider ) )
+        {
+            res = scmProvider.update( scmRepository, new ScmFileSet( checkoutDirectory ), makeScmVersion() );
+        }
+        else
+        {
+            res = checkOut( scmProvider, scmRepository, new ScmFileSet( checkoutDirectory ) );
+        }
+        return res;
+    }
+
+    private boolean checkoutDirExists( ScmProvider scmProvider )
+    {
+        String reservedScmFile = scmProvider.getScmSpecificFilename();
+        File pathToCheck = reservedScmFile == null ? checkoutDirectory : new File( checkoutDirectory, reservedScmFile );
+        return pathToCheck.exists();
+    }
+
     /**
      * @return a List&lt;String&gt; with filenames/directories at the resourcepath.
      * @see org.apache.maven.wagon.AbstractWagon#getFileList(java.lang.String)
@@ -795,15 +832,8 @@ public class ScmWagon
         }
     }
 
-    private String getFilename( String filename )
-    {
-        String fname = StringUtils.replace( filename, "/", File.separator );
-        return FileUtils.filename( fname );
-    }
-
-    private String getDirname( String filename )
+    private String getDirname( String resourceName )
     {
-        String fname = StringUtils.replace( filename, "/", File.separator );
-        return FileUtils.dirname( fname );
+        return FileUtils.getPath( resourceName, '/' );
     }
 }

-- 
To stop receiving notification emails like this one, please contact
michaelo@apache.org.

[maven-wagon] 02/03: [WAGON-497] ScmWagon#put() strips parent dirs from the target path if they already exist in SCM

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch wagon-scm-git
in repository https://gitbox.apache.org/repos/asf/maven-wagon.git

commit 66ce798b1d6375db1335a42570bed8d0978d4b79
Author: Ilya Basin <ba...@gmail.com>
AuthorDate: Sun Feb 18 12:31:46 2018 +0300

    [WAGON-497] ScmWagon#put() strips parent dirs from the target path if they already exist in SCM
    
    This closes #40
---
 .../java/org/apache/maven/wagon/WagonTestCase.java | 42 ++++++++++++++++------
 .../apache/maven/wagon/providers/scm/ScmWagon.java | 12 +++++--
 .../providers/scm/AbstractScmCvsWagonTest.java     |  2 +-
 3 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/wagon-provider-test/src/main/java/org/apache/maven/wagon/WagonTestCase.java b/wagon-provider-test/src/main/java/org/apache/maven/wagon/WagonTestCase.java
index fb277c7..e89f1e2 100644
--- a/wagon-provider-test/src/main/java/org/apache/maven/wagon/WagonTestCase.java
+++ b/wagon-provider-test/src/main/java/org/apache/maven/wagon/WagonTestCase.java
@@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -74,6 +75,10 @@ public abstract class WagonTestCase
         }
     }
 
+    protected static final String TEST_CONTENT = "test-resource.txt\n";
+
+    protected static final String TEST_CKSUM = cksum( TEST_CONTENT );
+
     protected static final String POM = "pom.xml";
 
     protected Repository localRepository;
@@ -233,16 +238,13 @@ public abstract class WagonTestCase
     public void testWagon()
         throws Exception
     {
-        if ( supportsGetIfNewer() )
-        {
-            setupRepositories();
+        setupRepositories();
 
-            setupWagonTestingFixtures();
+        setupWagonTestingFixtures();
 
-            fileRoundTripTesting();
+        fileRoundTripTesting();
 
-            tearDownWagonTestingFixtures();
-        }
+        tearDownWagonTestingFixtures();
     }
 
     public void testWagonGetIfNewerIsNewer()
@@ -341,7 +343,7 @@ public abstract class WagonTestCase
 
             assertNotNull( "check checksum is not null", checksumObserver.getActualChecksum() );
 
-            assertEquals( "compare checksums", "6b144b7285ffd6b0bc8300da162120b9",
+            assertEquals( "compare checksums", TEST_CKSUM,
                           checksumObserver.getActualChecksum() );
 
             // Now compare the contents of the artifact that was placed in
@@ -923,7 +925,7 @@ public abstract class WagonTestCase
     protected int putFile()
         throws Exception
     {
-        String content = "test-resource.txt\n";
+        String content = TEST_CONTENT;
         putFile( resource, "test-resource", content );
         return content.length();
     }
@@ -1049,7 +1051,7 @@ public abstract class WagonTestCase
 
         assertNotNull( "check checksum is not null", checksumObserver.getActualChecksum() );
 
-        assertEquals( "compare checksums", "6b144b7285ffd6b0bc8300da162120b9", checksumObserver.getActualChecksum() );
+        assertEquals( "compare checksums", TEST_CKSUM, checksumObserver.getActualChecksum() );
 
         checksumObserver = new ChecksumObserver();
 
@@ -1057,7 +1059,7 @@ public abstract class WagonTestCase
 
         assertNotNull( "check checksum is not null", checksumObserver.getActualChecksum() );
 
-        assertEquals( "compare checksums", "6b144b7285ffd6b0bc8300da162120b9", checksumObserver.getActualChecksum() );
+        assertEquals( "compare checksums", TEST_CKSUM, checksumObserver.getActualChecksum() );
 
         // Now compare the conents of the artifact that was placed in
         // the repository with the contents of the artifact that was
@@ -1087,4 +1089,22 @@ public abstract class WagonTestCase
         return repository;
     }
 
+    protected static String cksum( String content )
+    {
+        String checkSum;
+        try
+        {
+            ChecksumObserver obs = new ChecksumObserver();
+            byte[] buf = content.getBytes( StandardCharsets.ISO_8859_1 );
+            obs.transferProgress( null, buf, buf.length );
+            obs.transferCompleted( null );
+            checkSum = obs.getActualChecksum();
+        }
+        catch ( Exception e )
+        {
+            checkSum = null;
+        }
+        return checkSum;
+    }
+
 }
diff --git a/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java b/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java
index ceca314..09b014d 100644
--- a/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java
+++ b/wagon-providers/wagon-scm/src/main/java/org/apache/maven/wagon/providers/scm/ScmWagon.java
@@ -477,6 +477,7 @@ public class ScmWagon
         // and the configuration is incorrect. We will not try repo.getParent since most scm's don't
         // implement that.
 
+        target = target.replace( '\\', '/' );
         try
         {
             String repoUrl = getRepository().getUrl();
@@ -484,7 +485,11 @@ public class ScmWagon
             {
                 // Subversion is the only SCM that adds path structure to represent tags and branches.
                 // The rest use scmVersion and scmVersionType.
-                repoUrl += "/" + target.replace( '\\', '/' );
+                if ( target.length() > 0 )
+                {
+                    repoUrl += "/" + target;
+                    target = "";
+                }
             }
             scmRepository = getScmRepository( repoUrl );
 
@@ -502,7 +507,7 @@ public class ScmWagon
 
         // now create the subdirs in target, if it's a parent of targetName
 
-        String relPath = "";
+        String relPath = target.concat( target.length() > 0 ? "/" : "" );
 
         while ( !stack.isEmpty() )
         {
@@ -510,7 +515,8 @@ public class ScmWagon
             relPath += p + "/";
 
             File newDir = new File( checkoutDirectory, relPath );
-            if ( !newDir.mkdirs() )
+            newDir.mkdir();
+            if ( !newDir.isDirectory() )
             {
                 throw new TransferFailedException(
                     "Failed to create directory " + newDir.getAbsolutePath() + "; parent should exist: "
diff --git a/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/AbstractScmCvsWagonTest.java b/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/AbstractScmCvsWagonTest.java
index fc7b7f8..eac4562 100644
--- a/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/AbstractScmCvsWagonTest.java
+++ b/wagon-providers/wagon-scm/src/test/java/org/apache/maven/wagon/providers/scm/AbstractScmCvsWagonTest.java
@@ -41,6 +41,6 @@ public abstract class AbstractScmCvsWagonTest
     {
         String repository = getTestFile( "target/test-classes/test-repo-cvs" ).getAbsolutePath();
 
-        return "scm:cvs|local|" + repository + "|repository/newfolder";
+        return "scm:cvs|local|" + repository + "|repository";
     }
 }

-- 
To stop receiving notification emails like this one, please contact
michaelo@apache.org.