string fixes
[vng.git] / src / commands / Dist.cpp
blobd448aaed96fd85bcf8fcbb8edac755b63c8e5ec0
1 /*
2 * This file is part of the vng project
3 * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
4 * Copyright (C) 2002-2004 David Roundy
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "Dist.h"
21 #include "../CommandLineParser.h"
22 #include "../Logger.h"
23 #include "../GitRunner.h"
24 #include "../hunks/ChangeSet.h"
26 #include <QFile>
27 #include <QDir>
28 #include <QDebug>
29 #include <unistd.h>
31 static const CommandLineOption options[] = {
32 {"-d, --dist-name DISTNAME", "name of version"},
33 {"-j, --bzip2", "Create a tar-file with bzip2 compression"},
34 CommandLineLastOption
37 Dist::Dist()
38 : AbstractCommand("dist")
40 CommandLineParser::addOptionDefinitions(options);
43 AbstractCommand::ReturnCodes Dist::run()
45 if (! checkInRepository())
46 return NotInRepo;
47 moveToRoot();
49 CommandLineParser *args = CommandLineParser::instance();
50 QString name;
51 if (args->contains(QLatin1String("dist-name"))) {
52 name = args->optionArgument(QLatin1String("dist-name"));
53 } else {
54 QDir current = QDir::current();
55 name = current.dirName();
58 if (dryRun()) // not much use this command then...
59 return Ok;
61 // deletes our temp dir on exit of scope
62 struct Finalizer {
63 Finalizer(const QString &dirName) : tmp(dirName)
65 m_current = QDir::current();
67 ~Finalizer()
69 QDir::setCurrent(m_current.absolutePath());
70 rm(QFileInfo(m_current, tmp));
73 void rm(const QFileInfo &fi) {
74 if (fi.isDir()) {
75 QDir dir(fi.filePath());
76 foreach (QFileInfo fileInfo, dir.entryInfoList(QDir::Hidden | QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot))
77 rm(fileInfo);
79 else
80 QFile(fi.filePath()).remove();
81 m_current.rmpath(fi.filePath());
84 QString tmp;
85 QDir m_current;
88 QString tmpDirName;
89 int i = 0;
90 do {
91 tmpDirName = QString::fromLatin1("vng-tmp-%1").arg(i++);
92 } while (QFile(tmpDirName).exists());
94 if (! QDir::current().mkdir(tmpDirName) || ! QDir(tmpDirName).mkdir(name)) {
95 Logger::error() << "vng-failed; could not make a temporary dir\n";
97 Finalizer finalizer(tmpDirName);
99 QString basedir = tmpDirName + QDir::separator() + name + QDir::separator();
100 QList<File> filesToCheckout;
101 QList<File> allFiles = Commit::allFiles();
102 ChangeSet changeSet;
103 changeSet.fillFromCurrentChanges();
104 for (int i=0; i < changeSet.count(); ++i) {
105 File file = changeSet.file(i);
106 foreach (File other, allFiles) {
107 if (other.fileName() == file.fileName() || other.fileName() == file.oldFileName()) {
108 filesToCheckout << other;
109 allFiles.removeAll(other);
110 break;
115 QByteArray path (basedir.toLocal8Bit());
116 foreach (File file, allFiles) {
117 QByteArray dest = path;
118 QByteArray fileName = file.fileName();
119 dest.append(fileName);
120 #if defined (Q_OS_UNIX)
121 int rc = link(fileName.constData(), dest.constData());
122 if (rc == -1) { // this probably means the dirs should be created first.
123 int separator = dest.lastIndexOf(QString(QDir::separator()).toLocal8Bit());
124 Q_ASSERT(separator > 0);
125 QDir::current().mkpath(QString::fromLocal8Bit(dest.constData(), separator));
126 rc = link(fileName.constData(), dest.constData());
128 Q_ASSERT(rc == 0);
129 #else
130 Q_ASSERT(0); // remove when this is actually implemented
131 // Windows doesn't allow us to hardlink, so we are forced to copy the whole file.
132 // TODO copy file.
133 //bool success = Vng::copyFile(etc
134 #endif
137 foreach( File file, filesToCheckout) {
138 // checkout (changed) files to the tmp dir
139 QFile output(basedir + QString::fromLocal8Bit(file.fileName()));
140 Q_ASSERT(! output.exists());
141 QProcess git;
142 QStringList arguments;
143 arguments << QLatin1String("cat-file") << QLatin1String("blob") << file.sha1();
144 GitRunner runner(git, arguments);
145 ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput);
146 if (rc == Ok) {
147 bool success = Vng::copyFile(git, output);
148 git.waitForFinished();
149 output.close();
150 if (!success)
151 return WriteError;
153 output.setPermissions(file.permissions());
156 const bool bzip2 = args->contains(QLatin1String("bzip2"));
157 QString outFileName;
158 if (bzip2)
159 outFileName = name + QLatin1String(".tar.bz2");
160 else
161 outFileName = name + QLatin1String(".tgz");
162 Logger::debug() << "will write out " << outFileName << endl;
164 // chdir
165 QDir::setCurrent(tmpDirName);
166 QProcess tar;
167 QStringList arguments;
168 arguments.append(QString::fromLatin1("c") + (bzip2 ? QLatin1Char('j') : QLatin1Char('z')) + QLatin1String("f"));
169 arguments << QLatin1String("../")+outFileName << name;
170 tar.start(QLatin1String("tar"), arguments , 0);
171 tar.waitForFinished(-1);
172 if (tar.exitCode() != 0) {
173 Logger::error() << "vng-failed: The tar subprocess reported errorcode "
174 << QString::number(tar.exitCode()) << endl;
175 return OtherVngError;
177 Logger::standardOut() << "Created dist as " << outFileName << endl;
179 return Ok;
182 QString Dist::argumentDescription() const
184 return QString();
187 QString Dist::commandDescription() const
189 return QLatin1String("Dist is a handy tool for implementing a \"make dist\" target in your\n"
190 "makefile. It creates a tarball of the recorded edition of your tree.\n");