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 *
047 */
048public class LocalUpdateCommand extends AbstractUpdateCommand implements LocalCommand {
049    /** {@inheritDoc} */
050    protected UpdateScmResult executeUpdateCommand(ScmProviderRepository repo, ScmFileSet fileSet, ScmVersion version)
051            throws ScmException {
052        LocalScmProviderRepository repository = (LocalScmProviderRepository) repo;
053
054        if (version != null) {
055            throw new ScmException("The local scm doesn't support tags.");
056        }
057
058        File root = new File(repository.getRoot());
059
060        String module = repository.getModule();
061
062        File source = new File(root, module);
063
064        File baseDestination = fileSet.getBasedir();
065
066        if (!baseDestination.exists()) {
067            throw new ScmException("The working directory doesn't exist (" + baseDestination.getAbsolutePath() + ").");
068        }
069
070        if (!root.exists()) {
071            throw new ScmException("The base directory doesn't exist (" + root.getAbsolutePath() + ").");
072        }
073
074        if (!source.exists()) {
075            throw new ScmException("The module directory doesn't exist (" + source.getAbsolutePath() + ").");
076        }
077
078        if (!baseDestination.exists() && !baseDestination.isDirectory()) {
079            throw new ScmException("The destination directory isn't a directory or doesn't exist ("
080                    + baseDestination.getAbsolutePath() + ").");
081        }
082
083        List<ScmFile> updatedFiles;
084
085        try {
086            if (logger.isInfoEnabled()) {
087                logger.info("Updating '" + baseDestination.getAbsolutePath() + "' from '" + source.getAbsolutePath()
088                        + "'.");
089            }
090
091            List<File> fileList = FileUtils.getFiles(source.getAbsoluteFile(), "**", null);
092            updatedFiles = update(source, baseDestination, fileList);
093
094            // process deletions in repository
095            LocalScmMetadataUtils metadataUtils = new LocalScmMetadataUtils();
096            LocalScmMetadata originalMetadata = metadataUtils.readMetadata(baseDestination);
097            if (originalMetadata != null) {
098                LocalScmMetadata newMetadata = metadataUtils.buildMetadata(source);
099                for (Iterator<String> it =
100                                originalMetadata.getRepositoryFileNames().iterator();
101                        it.hasNext(); ) {
102                    String filename = it.next();
103                    if (!newMetadata.getRepositoryFileNames().contains(filename)) {
104                        File localFile = new File(baseDestination, filename);
105                        if (localFile.exists()) {
106                            localFile.delete();
107                            updatedFiles.add(new ScmFile("/" + filename, ScmFileStatus.UPDATED));
108                        }
109                    }
110                }
111            }
112
113            // rewrite metadata file
114            metadataUtils.writeMetadata(baseDestination, metadataUtils.buildMetadata(source));
115
116        } catch (IOException ex) {
117            throw new ScmException("Error while checking out the files.", ex);
118        }
119
120        return new LocalUpdateScmResult(null, updatedFiles);
121    }
122
123    private List<ScmFile> update(File source, File baseDestination, List<File> files) throws ScmException, IOException {
124        String sourcePath = source.getAbsolutePath();
125
126        List<ScmFile> updatedFiles = new ArrayList<>();
127
128        for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
129            File repositoryFile = i.next();
130
131            String dest = repositoryFile.getAbsolutePath().substring(sourcePath.length() + 1);
132
133            File destinationFile = new File(baseDestination, dest);
134
135            String repositoryFileContents = FileUtils.fileRead(repositoryFile);
136
137            if (destinationFile.exists()) {
138                String destionationFileContents = FileUtils.fileRead(destinationFile);
139
140                if (repositoryFileContents.equals(destionationFileContents)) {
141                    continue;
142                }
143            }
144
145            File destinationDirectory = destinationFile.getParentFile();
146
147            if (!destinationDirectory.exists() && !destinationDirectory.mkdirs()) {
148                throw new ScmException(
149                        "Could not create destination directory '" + destinationDirectory.getAbsolutePath() + "'.");
150            }
151
152            ScmFileStatus status;
153
154            if (destinationFile.exists()) {
155                status = ScmFileStatus.UPDATED;
156            } else {
157                status = ScmFileStatus.ADDED;
158            }
159
160            FileUtils.copyFileToDirectory(repositoryFile, destinationDirectory);
161
162            int chop = baseDestination.getAbsolutePath().length();
163
164            String fileName = destinationFile.getAbsolutePath().substring(chop + 1);
165
166            updatedFiles.add(new ScmFile(fileName, status));
167        }
168
169        return updatedFiles;
170    }
171
172    /** {@inheritDoc} */
173    protected ChangeLogCommand getChangeLogCommand() {
174        return new LocalChangeLogCommand();
175    }
176}