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            File repositoryDirectory = repositoryFile.getParentFile();
132
133            String dest = repositoryFile.getAbsolutePath().substring(sourcePath.length() + 1);
134
135            File destinationFile = new File(baseDestination, dest);
136
137            String repositoryFileContents = FileUtils.fileRead(repositoryFile);
138
139            if (destinationFile.exists()) {
140                String destionationFileContents = FileUtils.fileRead(destinationFile);
141
142                if (repositoryFileContents.equals(destionationFileContents)) {
143                    continue;
144                }
145            }
146
147            File destinationDirectory = destinationFile.getParentFile();
148
149            if (!destinationDirectory.exists() && !destinationDirectory.mkdirs()) {
150                throw new ScmException(
151                        "Could not create destination directory '" + destinationDirectory.getAbsolutePath() + "'.");
152            }
153
154            ScmFileStatus status;
155
156            if (destinationFile.exists()) {
157                status = ScmFileStatus.UPDATED;
158            } else {
159                status = ScmFileStatus.ADDED;
160            }
161
162            FileUtils.copyFileToDirectory(repositoryFile, destinationDirectory);
163
164            int chop = baseDestination.getAbsolutePath().length();
165
166            String fileName = destinationFile.getAbsolutePath().substring(chop + 1);
167
168            updatedFiles.add(new ScmFile(fileName, status));
169        }
170
171        return updatedFiles;
172    }
173
174    /** {@inheritDoc} */
175    protected ChangeLogCommand getChangeLogCommand() {
176        return new LocalChangeLogCommand();
177    }
178}