monotone

monotone Mtn Source Tree

Root/git.cc

1// -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*-
2// vim:sw=2:
3// Copyright (C) 2005 Petr Baudis <pasky@suse.cz>
4// all rights reserved.
5// licensed to the public under the terms of the GNU GPL (>= 2)
6// see the file COPYING for details
7
8// Common utility functions for manipulating GIT-related stuff
9// and communicating with GIT itself.
10// Sponsored by Google's Summer of Code and SuSE
11
12#include <algorithm>
13#include <iostream>
14#include <fstream>
15#include <iterator>
16#include <list>
17#include <map>
18#include <set>
19#include <sstream>
20#include <stack>
21#include <stdexcept>
22#include <string>
23#include <vector>
24#include <queue>
25#include <stdlib.h>
26
27#ifndef WIN32
28
29#include <unistd.h>
30
31#include <stdio.h>
32#include <string.h> // strdup(), woo-hoo!
33
34#include <boost/shared_ptr.hpp>
35#include <boost/scoped_ptr.hpp>
36#include <boost/lexical_cast.hpp>
37#include <boost/tokenizer.hpp>
38
39#include <boost/filesystem/path.hpp>
40#include <boost/filesystem/operations.hpp>
41#include <boost/filesystem/convenience.hpp>
42
43#include "app_state.hh"
44#include "cert.hh"
45#include "constants.hh"
46#include "database.hh"
47#include "file_io.hh"
48#include "git.hh"
49#include "mkstemp.hh"
50#include "revision.hh"
51#include "transforms.hh"
52
53using namespace std;
54using boost::shared_ptr;
55using boost::scoped_ptr;
56
57
58string const gitcommit_id_cert_name = "gitcommit-id";
59string const gitcommit_committer_cert_name = "gitcommit-committer";
60
61
62void
63set_git_env(string const & name, string const & value)
64{
65 char *env_entry = strdup((name + "=" + value).c_str());
66 putenv(env_entry);
67}
68
69void
70stream_grabline(istream &stream, string &line)
71{
72 // You can't hate C++ as much as I do.
73 char linebuf[256];
74 stream.getline(linebuf, 256);
75 line = linebuf;
76}
77
78int
79git_tmpfile(string &tmpfile)
80{
81 char *tmpdir = getenv("TMPDIR");
82 if (!tmpdir)
83 tmpdir = "/tmp";
84
85 tmpfile = string(tmpdir);
86 tmpfile += "/mtgit.XXXXXX";
87 return monotone_mkstemp(tmpfile);
88}
89
90
91void
92capture_git_cmd_output(boost::format const & fmt, filebuf &fb)
93{
94 string str;
95 try
96 {
97 str = fmt.str();
98 }
99 catch (std::exception & e)
100 {
101 P(F("capture_git_cmd_output() formatter failed: %s") % e.what());
102 throw e;
103 }
104
105 string tmpfile;
106 int fd = git_tmpfile(tmpfile);
107
108 string cmdline("(" + str + ") >" + tmpfile);
109 L(F("Capturing cmd output: %s") % cmdline);
110 N(system(cmdline.c_str()) == 0,
111 F("git command %s failed") % str);
112 fb.open(tmpfile.c_str(), ios::in);
113 close(fd);
114 delete_file(system_path(tmpfile));
115}
116
117void
118capture_git_cmd_io(boost::format const & fmt, data const &input, filebuf &fbout)
119{
120 string str;
121 try
122 {
123 str = fmt.str();
124 }
125 catch (std::exception & e)
126 {
127 P(F("capture_git_cmd_io() formatter failed: %s") % e.what());
128 throw e;
129 }
130
131 string intmpfile;
132 {
133 int fd = git_tmpfile(intmpfile);
134 filebuf fb;
135 fb.open(intmpfile.c_str(), ios::out);
136 close(fd);
137 ostream stream(&fb);
138 stream << input();
139 }
140
141 string outtmpfile;
142 int fd = git_tmpfile(outtmpfile);
143 string cmdline("(" + str + ") <" + intmpfile + " >" + outtmpfile);
144 L(F("Feeding cmd input and grabbing output: %s") % cmdline);
145 N(system(cmdline.c_str()) == 0,
146 F("git command %s failed") % str);
147 fbout.open(outtmpfile.c_str(), ios::in);
148 close(fd);
149 delete_file(system_path(outtmpfile));
150 delete_file(system_path(intmpfile));
151}
152
153
154// Look up given GIT commit id in present monotone history;
155// this is used for incremental import. Being smart, it also
156// populates the commitmap with GIT commits it finds along the way.
157void
158historical_gitrev_to_monorev(string const &branch, git_mt_commitmap *commitmap,
159 app_state &app,
160 git_object_id gitrid, revision_id &found_rid)
161{
162 queue<revision_id> frontier;
163 set<revision_id> seen;
164
165 // All the ancestry should be at least already in our branch, so there is
166 // no need to work over the whole database.
167 set<revision_id> heads;
168 get_branch_heads(branch, app, heads);
169 for (set<revision_id>::const_iterator i = heads.begin();
170 i != heads.end(); ++i)
171 frontier.push(*i);
172
173 while (!frontier.empty())
174 {
175 revision_id rid = frontier.front(); frontier.pop();
176
177 if (seen.find(rid) != seen.end())
178 continue;
179 seen.insert(rid);
180
181 revision_set rev;
182 app.db.get_revision(rid, rev);
183
184 vector<revision<cert> > certs;
185 app.db.get_revision_certs(rid, gitcommit_id_cert_name, certs);
186 I(certs.size() < 2);
187 if (certs.size() > 0)
188 {
189 // This is a GIT commit, then.
190 cert_value cv;
191 decode_base64(certs[0].inner().value, cv);
192 git_object_id gitoid = cv();
193
194 if (commitmap)
195 (*commitmap)[gitoid()] = make_pair(rid, rev.new_manifest);
196
197 if (gitoid == gitrid)
198 {
199 found_rid = rid;
200 return;
201 }
202 }
203
204 for (edge_map::const_iterator e = rev.edges.begin();
205 e != rev.edges.end(); ++e)
206 {
207 frontier.push(edge_old_revision(e));
208 }
209 }
210
211 N(false,
212 F("Wicked revision tree - incremental import wanted to import a GIT commit\n"
213 "whose parent is not in the Monotone database yet. This means a hole must\n"
214 "have popped up in the Monotone revision history."));
215}
216
217#endif

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status