]> andersk Git - svn-all-fast-export.git/blob - src/repository.cpp
Add support for branch creation on-the-fly
[svn-all-fast-export.git] / src / repository.cpp
1 /*
2  *  Copyright (C) 2007  Thiago Macieira <thiago@kde.org>
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "repository.h"
19 #include <QTextStream>
20 #include <QDebug>
21
22 Repository::Repository(const Rules::Repository &rule)
23     : name(rule.name)
24 {
25     foreach (Rules::Repository::Branch branchRule, rule.branches) {
26         Branch branch;
27         branch.branchFrom = branchRule.branchFrom;
28         if (!branch.branchFrom.startsWith("refs/"))
29             branch.branchFrom.prepend("refs/heads/");
30         branch.isCreated = false;
31
32         branches.insert(branchRule.name, branch);
33     }
34
35     // create the default branch
36     branches["master"].isCreated = true;
37
38     fastImport.setWorkingDirectory(name);
39 }
40
41 Repository::~Repository()
42 {
43     if (fastImport.state() != QProcess::NotRunning) {
44         fastImport.closeWriteChannel();
45         fastImport.waitForFinished();
46     }
47 }
48
49 void Repository::reloadBranches()
50 {
51     QHash<QString, Branch>::Iterator it = branches.begin(),
52                                     end = branches.end();
53     for ( ; it != end; ++it) {
54         QString branchRef = it.key();
55         if (!branchRef.startsWith("refs/"))
56             branchRef.prepend("refs/heads/");
57
58         bool branchExists;
59         // does this branch already exist?
60         QProcess revParse;
61         revParse.setWorkingDirectory(name);
62         revParse.start("git-rev-parse", QStringList() << "--verify" << branchRef);
63         revParse.waitForFinished();
64
65         if (revParse.exitCode() == 0)
66             branchExists = true;
67         else
68             branchExists = false;
69
70         if (branchExists) {
71             startFastImport();
72             fastImport.write("reset " + branchRef.toUtf8() +
73                              "\nfrom " + branchRef.toUtf8() + "^0\n\n");
74             it->isCreated = true;
75         }
76     }
77 }
78
79 void Repository::createBranch(const QString &branch, int revnum,
80                               const QString &branchFrom, int)
81 {
82     if (!branches.contains(branch)) {
83         qCritical() << branch << "is not a known branch in repository" << name;
84         exit(1);
85     }
86
87     startFastImport();
88     QByteArray branchRef = branch.toUtf8();
89     if (!branchRef.startsWith("refs/"))
90         branchRef.prepend("refs/heads/");
91
92     Branch &br = branches[branch];
93     if (br.isCreated) {
94         QByteArray backupBranch = branchRef + '_' + QByteArray::number(revnum);
95         qWarning() << branch << "already exists; backing up to" << backupBranch;
96
97         fastImport.write("reset " + backupBranch + "\nfrom " + branchRef + "\n\n");
98     }
99
100     // now create the branch
101     br.isCreated = true;
102     QByteArray branchFromRef = branchFrom.toUtf8();
103     if (!branchFromRef.startsWith("refs/"))
104         branchFromRef.prepend("refs/heads/");
105
106     fastImport.write("reset " + branchRef + "\nfrom " + branchFromRef + "\n\n");
107 }
108
109 Repository::Transaction *Repository::newTransaction(const QString &branch, const QString &svnprefix,
110                                                     int revnum)
111 {
112     if (!branches.contains(branch)) {
113         qCritical() << branch << "is not a known branch in repository" << name;
114         return 0;
115     }
116
117     Transaction *txn = new Transaction;
118     txn->repository = this;
119     txn->branch = branch.toUtf8();
120     txn->svnprefix = svnprefix.toUtf8();
121     txn->datetime = 0;
122     txn->revnum = revnum;
123     txn->lastmark = revnum;
124
125     startFastImport();
126     return txn;
127 }
128
129 void Repository::startFastImport()
130 {
131     if (fastImport.state() == QProcess::NotRunning) {
132         // start the process
133 #ifndef DRY_RUN
134         fastImport.setProcessChannelMode(QProcess::ForwardedChannels);
135         fastImport.start("git-fast-import", QStringList());
136 #else
137         fastImport.setStandardOutputFile(name);
138         fastImport.start("/bin/cat", QStringList());
139 #endif
140     }
141 }
142
143 Repository::Transaction::~Transaction()
144 {
145 }
146
147 void Repository::Transaction::setAuthor(const QByteArray &a)
148 {
149     author = a;
150 }
151
152 void Repository::Transaction::setDateTime(uint dt)
153 {
154     datetime = dt;
155 }
156
157 void Repository::Transaction::setLog(const QByteArray &l)
158 {
159     log = l;
160 }
161
162 void Repository::Transaction::deleteFile(const QString &path)
163 {
164     deletedFiles.append(path);
165 }
166
167 QIODevice *Repository::Transaction::addFile(const QString &path, int mode, qint64 length)
168 {
169     FileProperties fp;
170     fp.mode = mode;
171     fp.mark = ++lastmark;
172
173 #ifndef DRY_RUN
174     repository->fastImport.write("blob\nmark :");
175     repository->fastImport.write(QByteArray::number(fp.mark));
176     repository->fastImport.write("\ndata ");
177     repository->fastImport.write(QByteArray::number(length));
178     repository->fastImport.write("\n", 1);
179     repository->fastImport.waitForBytesWritten(0);
180 #endif
181
182     modifiedFiles.insert(path, fp);
183     return &repository->fastImport;
184 }
185
186 void Repository::Transaction::commit()
187 {
188     // create the commit message
189     QByteArray message = log;
190     if (!message.endsWith('\n'))
191         message += '\n';
192     message += "\nsvn path=" + svnprefix + "; revision=" + QByteArray::number(revnum) + "\n";
193
194     {
195         QByteArray branchRef = branch;
196         if (!branchRef.startsWith("refs/"))
197             branchRef.prepend("refs/heads/");
198
199         QTextStream s(&repository->fastImport);
200         s << "commit " << branchRef << endl;
201         s << "mark :" << revnum << endl;
202         s << "committer " << author << ' ' << datetime << " -0000" << endl;
203
204         Branch &br = repository->branches[branch];
205         if (!br.isCreated) {
206             br.isCreated = true;
207             s << "from " << br.branchFrom << endl;
208         }
209
210         s << "data " << message.length() << endl;
211     }
212
213     repository->fastImport.write(message);
214
215     // write the file deletions
216     foreach (QString df, deletedFiles)
217         repository->fastImport.write("D " + df.toUtf8() + "\n");
218
219     // write the file modifications
220     QHash<QString, FileProperties>::ConstIterator it = modifiedFiles.constBegin();
221     for ( ; it != modifiedFiles.constEnd(); ++it) {
222         repository->fastImport.write("M ", 2);
223         repository->fastImport.write(QByteArray::number(it->mode, 8));
224         repository->fastImport.write(" :", 2);
225         repository->fastImport.write(QByteArray::number(it->mark));
226         repository->fastImport.write(" ", 1);
227         repository->fastImport.write(it.key().toUtf8());
228         repository->fastImport.write("\n", 1);
229     }
230
231     repository->fastImport.write("\n");
232
233     while (repository->fastImport.bytesToWrite() && repository->fastImport.waitForBytesWritten()) {
234         // nothing
235     }
236 }
This page took 0.045806 seconds and 5 git commands to generate.