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/>.
21 #include "../CommandLineParser.h"
22 #include "../Logger.h"
23 #include "../GitRunner.h"
24 #include "../hunks/ChangeSet.h"
31 static const CommandLineOption options
[] = {
32 {"-d, --dist-name DISTNAME", "name of version"},
33 {"-j, --bzip2", "Create a tar-file with bzip2 compression"},
38 : AbstractCommand("dist")
40 CommandLineParser::addOptionDefinitions(options
);
43 AbstractCommand::ReturnCodes
Dist::run()
45 if (! checkInRepository())
49 CommandLineParser
*args
= CommandLineParser::instance();
51 if (args
->contains(QLatin1String("dist-name"))) {
52 name
= args
->optionArgument(QLatin1String("dist-name"));
54 QDir current
= QDir::current();
55 name
= current
.dirName();
58 if (dryRun()) // not much use this command then...
61 // deletes our temp dir on exit of scope
63 Finalizer(const QString
&dirName
) : tmp(dirName
)
65 m_current
= QDir::current();
69 QDir::setCurrent(m_current
.absolutePath());
70 rm(QFileInfo(m_current
, tmp
));
73 void rm(const QFileInfo
&fi
) {
75 QDir
dir(fi
.filePath());
76 foreach (QFileInfo fileInfo
, dir
.entryInfoList(QDir::Hidden
| QDir::Files
| QDir::Dirs
| QDir::NoDotAndDotDot
))
80 QFile(fi
.filePath()).remove();
81 m_current
.rmpath(fi
.filePath());
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();
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
);
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());
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.
133 //bool success = Vng::copyFile(etc
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());
142 QStringList arguments
;
143 arguments
<< QLatin1String("cat-file") << QLatin1String("blob") << file
.sha1();
144 GitRunner
runner(git
, arguments
);
145 ReturnCodes rc
= runner
.start(GitRunner::WaitForStandardOutput
);
147 bool success
= Vng::copyFile(git
, output
);
148 git
.waitForFinished();
153 output
.setPermissions(file
.permissions());
156 const bool bzip2
= args
->contains(QLatin1String("bzip2"));
159 outFileName
= name
+ QLatin1String(".tar.bz2");
161 outFileName
= name
+ QLatin1String(".tgz");
162 Logger::debug() << "will write out " << outFileName
<< endl
;
165 QDir::setCurrent(tmpDirName
);
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
;
182 QString
Dist::argumentDescription() const
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");