001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.scm.provider.local.command.update;
020
021import java.io.File;
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.Iterator;
025import java.util.List;
026
027import org.apache.maven.scm.ScmException;
028import org.apache.maven.scm.ScmFile;
029import org.apache.maven.scm.ScmFileSet;
030import org.apache.maven.scm.ScmFileStatus;
031import org.apache.maven.scm.ScmVersion;
032import org.apache.maven.scm.command.changelog.ChangeLogCommand;
033import org.apache.maven.scm.command.update.AbstractUpdateCommand;
034import org.apache.maven.scm.command.update.UpdateScmResult;
035import org.apache.maven.scm.provider.ScmProviderRepository;
036import org.apache.maven.scm.provider.local.command.LocalCommand;
037import org.apache.maven.scm.provider.local.command.changelog.LocalChangeLogCommand;
038import org.apache.maven.scm.provider.local.metadata.LocalScmMetadata;
039import org.apache.maven.scm.provider.local.metadata.LocalScmMetadataUtils;
040import org.apache.maven.scm.provider.local.repository.LocalScmProviderRepository;
041import org.codehaus.plexus.util.FileUtils;
042
043/**
044 * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
045 * @author Olivier Lamy
046 */
047public class LocalUpdateCommand extends AbstractUpdateCommand implements LocalCommand {
048    /**
049     * {@inheritDoc}
050     */
051    protected UpdateScmResult executeUpdateCommand(ScmProviderRepository repo, ScmFileSet fileSet, ScmVersion version)
052            throws ScmException {
053        LocalScmProviderRepository repository = (LocalScmProviderRepository) repo;
054
055        if (version != null) {
056            throw new ScmException("The local scm doesn't support tags.");
057        }
058
059        File root = new File(repository.getRoot());
060
061        String module = repository.getModule();
062
063        File source = new File(root, module);
064
065        File baseDestination = fileSet.getBasedir();
066
067        if (!baseDestination.exists()) {
068            throw new ScmException("The working directory doesn't exist (" + baseDestination.getAbsolutePath() + ").");
069        }
070
071        if (!root.exists()) {
072            throw new ScmException("The base directory doesn't exist (" + root.getAbsolutePath() + ").");
073        }
074
075        if (!source.exists()) {
076            throw new ScmException("The module directory doesn't exist (" + source.getAbsolutePath() + ").");
077        }
078
079        if (!baseDestination.exists() && !baseDestination.isDirectory()) {
080            throw new ScmException("The destination directory isn't a directory or doesn't exist ("
081                    + baseDestination.getAbsolutePath() + ").");
082        }
083
084        List<ScmFile> updatedFiles;
085
086        try {
087            if (logger.isInfoEnabled()) {
088                logger.info("Updating '" + baseDestination.getAbsolutePath() + "' from '" + source.getAbsolutePath()
089                        + "'.");
090            }
091
092            List<File> fileList = FileUtils.getFiles(source.getAbsoluteFile(), "**", null);
093            updatedFiles = update(source, baseDestination, fileList);
094
095            // process deletions in repository
096            LocalScmMetadataUtils metadataUtils = new LocalScmMetadataUtils();
097            LocalScmMetadata originalMetadata = metadataUtils.readMetadata(baseDestination);
098            if (originalMetadata != null) {
099                LocalScmMetadata newMetadata = metadataUtils.buildMetadata(source);
100                for (Iterator<String> it =
101                                originalMetadata.getRepositoryFileNames().iterator();
102                        it.hasNext(); ) {
103                    String filename = it.next();
104                    if (!newMetadata.getRepositoryFileNames().contains(filename)) {
105                        File localFile = new File(baseDestination, filename);
106                        if (localFile.exists()) {
107                            localFile.delete();
108                            updatedFiles.add(new ScmFile("/" + filename, ScmFileStatus.UPDATED));
109                        }
110                    }
111                }
112            }
113
114            // rewrite metadata file
115            metadataUtils.writeMetadata(baseDestination, metadataUtils.buildMetadata(source));
116
117        } catch (IOException ex) {
118            throw new ScmException("Error while checking out the files.", ex);
119        }
120
121        return new LocalUpdateScmResult(null, updatedFiles);
122    }
123
124    private List<ScmFile> update(File source, File baseDestination, List<File> files) throws ScmException, IOException {
125        String sourcePath = source.getAbsolutePath();
126
127        List<ScmFile> updatedFiles = new ArrayList<>();
128
129        for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
130            File repositoryFile = i.next();
131
132            String dest = repositoryFile.getAbsolutePath().substring(sourcePath.length() + 1);
133
134            File destinationFile = new File(baseDestination, dest);
135
136            String repositoryFileContents = FileUtils.fileRead(repositoryFile);
137
138            if (destinationFile.exists()) {
139                String destionationFileContents = FileUtils.fileRead(destinationFile);
140
141                if (repositoryFileContents.equals(destionationFileContents)) {
142                    continue;
143                }
144            }
145
146            File destinationDirectory = destinationFile.getParentFile();
147
148            if (!destinationDirectory.exists() && !destinationDirectory.mkdirs()) {
149                throw new ScmException(
150                        "Could not create destination directory '" + destinationDirectory.getAbsolutePath() + "'.");
151            }
152
153            ScmFileStatus status;
154
155            if (destinationFile.exists()) {
156                status = ScmFileStatus.UPDATED;
157            } else {
158                status = ScmFileStatus.ADDED;
159            }
160
161            FileUtils.copyFileToDirectory(repositoryFile, destinationDirectory);
162
163            int chop = baseDestination.getAbsolutePath().length();
164
165            String fileName = destinationFile.getAbsolutePath().substring(chop + 1);
166
167            updatedFiles.add(new ScmFile(fileName, status));
168        }
169
170        return updatedFiles;
171    }
172
173    /**
174     * {@inheritDoc}
175     */
176    protected ChangeLogCommand getChangeLogCommand() {
177        return new LocalChangeLogCommand();
178    }
179}