Example #1
0
// Loads a revision from the cache
Revision *Cache::get(const std::string &id)
{
	if (!m_loaded) {
		load();
	}

	std::string dir = cacheDir();
	std::pair<uint32_t, uint32_t> offset = m_index[id];
	std::string path = str::printf("%s/cache.%u", dir.c_str(), offset.first);
	if (m_cin == NULL || offset.first != m_ciindex) {
		delete m_cin;
		m_cin = new BIStream(path);
		m_ciindex = offset.first;
		if (!m_cin->ok()) {
			throw PEX(str::printf("Unable to read from cache file: %s", path.c_str()));
		}
	}
	if (!m_cin->seek(offset.second)) {
		throw PEX(str::printf("Unable to read from cache file: %s", path.c_str()));
	}

	Revision *rev = new Revision(id);
	std::vector<char> data;
	*m_cin >> data;
	data = utils::uncompress(data);
	if (data.empty()) {
		throw PEX(str::printf("Unable to read from cache file: %s", path.c_str()));
	}
	MIStream rin(data);
	if (!rev->load03(rin)) {
		throw PEX(str::printf("Unable to read from cache file: %s", path.c_str()));
	}
	return rev;
}
Example #2
0
// Searches the current PATH for the given program
std::string which(const std::string &program)
{
	std::string progPath;
	char *path = getenv("PATH");
	if (path == NULL) {
		throw PEX("PATH is not set");
	}
	std::vector<std::string> ls;
#ifdef POS_WIN
	ls = str::split(path, ";");
#else
	ls = str::split(path, ":");
#endif
	for (size_t i = 0; i < ls.size(); i++) {
		std::string t = ls[i] + "/" + program;
#ifdef POS_WIN
		t += ".exe";
#endif
		if (sys::fs::fileExecutable(t)) {
			progPath = t;
			break;
		}
	}

	if (progPath.empty()) {
		throw PEX(std::string("Can't find ") + program + " in PATH");
	}
	return progPath;
}
Example #3
0
// Loads the index file
void Cache::load()
{
	std::string path = cacheDir();
	PDEBUG << "Using cache dir: " << path << endl;

	m_index.clear();
	m_loaded = true;

	bool created;
	checkDir(path, &created);
	lock();
	if (created) {
		return;
	}

	// For git repositories, the hardest part is calling uuid()
	sys::datetime::Watch watch;

	GZIStream *in = new GZIStream(path+"/index");
	if (!in->ok()) {
		Logger::info() << "Cache: Empty cache for '" << uuid() << '\'' << endl;
		return;
	}

	uint32_t version;
	*in >> version;
	switch (checkVersion(version)) {
		case OutOfDate:
			delete in;
			throw PEX(str::printf("Cache is out of date - please run the check_cache report", version));
		case UnknownVersion:
			delete in;
			throw PEX(str::printf("Unknown cache version number %u - please run the check_cache report", version));
		default:
			break;
	}

	Logger::status() << "Loading cache index... " << ::flush;

	std::string buffer;
	std::pair<uint32_t, uint32_t> pos;
	uint32_t crc;
	while (!(*in >> buffer).eof()) {
		if (buffer.empty()) {
			break;
		}
		*in >> pos.first >> pos.second;
		*in >> crc;
		m_index[buffer] = pos;
	}

	Logger::status() << "done" << endl;
	delete in;
	Logger::info() << "Cache: Loaded " << m_index.size() << " revisions in " << watch.elapsedMSecs() << " ms" << endl;
}
Example #4
0
Revision *LdbCache::get(const std::string &id)
{
	if (!m_db) opendb();

	std::string value;
	leveldb::Status s = m_db->Get(leveldb::ReadOptions(), id, &value);
	if (!s.ok()) {
		throw PEX(str::printf("Error reading from cache: %s", s.ToString().c_str()));
	}

	Revision *rev = new Revision(id);
	MIStream rin(value.c_str(), value.length());
	if (!rev->load(rin)) {
		throw PEX(str::printf("Unable to read from cache: Data corrupted"));
	}
	return rev;
}
Example #5
0
// Constructor
Mutex::Mutex()
{
	int ret = pthread_mutex_init(&m_pmx, NULL);
	switch (ret) {
		case 0: break;
		case EBUSY: throw PEX("Mutex is locked by a thread");
		default: throw PEX_ERR(ret);
	}
}
Example #6
0
// Wrapper for strptime()
int64_t ptime(const std::string &str, const std::string &format)
{
	struct tm time;
	memset(&time, 0x00, sizeof(struct tm));
	if (strptime(str.c_str(), format.c_str(), &time) == NULL) {
		throw PEX(std::string("Error parsing time '" + str + "' with format '" + format + "'"));
	}
	return mktime(&time);
}
Example #7
0
// Destructor
Mutex::~Mutex()
{
	int ret = pthread_mutex_destroy(&m_pmx);
	switch (ret) {
		case 0: break;
		case EBUSY: throw PEX("Mutex is locked by a thread");
		default: throw PEX_ERR(ret);
	}
}
Example #8
0
// Wrapper for pthread_cancel()
void Thread::cancel()
{
	int ret = pthread_cancel(m_pth);
	switch (ret) {
		case 0: break;
		case ESRCH: throw PEX("No such thread");
		default: throw PEX_ERR(ret);
	}
}
Example #9
0
// Adds the revision to the cache
void LdbCache::put(const std::string &id, const Revision &rev)
{
	if (!m_db) opendb();

	MOStream rout;
	rev.write(rout);
	std::vector<char> data(rout.data());
	leveldb::Status s = m_db->Put(leveldb::WriteOptions(), id, std::string(data.begin(), data.end()));
	if (!s.ok()) {
		throw PEX(str::printf("Error writing to cache: %s", s.ToString().c_str()));
	}
}
Example #10
0
// Locks the cache directory for this process
void Cache::lock()
{
	if (m_lock >= 0) {
		PDEBUG << "Already locked (" << m_lock << ")" << endl;
		return;
	}

	std::string path = cacheDir();
	std::string lock = path + "/lock";
	m_lock = ::open(lock.c_str(), O_WRONLY | O_CREAT, S_IWUSR);
	if (m_lock == -1) {
		throw PEX(str::printf("Unable to lock cache %s: %s", path.c_str(), PepperException::strerror(errno).c_str()));
	}

	PTRACE << "Locking file " << lock << endl;
	struct flock flck;
	memset(&flck, 0x00, sizeof(struct flock));
	flck.l_type = F_WRLCK;
	if (fcntl(m_lock, F_SETLK, &flck) == -1) {
		throw PEX(str::printf("Unable to lock cache %s, it may be used by another instance", path.c_str()));
	}
}
Example #11
0
// Creates a temporary file
std::string Plot::tempfile(std::ofstream &out)
{
	std::string path;
	sys::fs::mkstemp(&path);

	out.open(path.c_str());
	if (out.bad()) {
		throw PEX(str::printf("Unable to open temporary file '%s'", path.c_str()));
	}

	m_tempfiles.push_back(path);
	return path;
}
Example #12
0
// Checks if the diffstat of the given revision is already cached
bool LdbCache::lookup(const std::string &id)
{
	if (!m_db) opendb();

	std::string value;
	leveldb::Status s = m_db->Get(leveldb::ReadOptions(), id, &value);
	if (s.IsNotFound()) {
		return false;
	}
	if (!s.ok()) {
		throw PEX(str::printf("Error reading from cache: %s", s.ToString().c_str()));
	}
	return true;
}
Example #13
0
// Unlocks the cache directory
void Cache::unlock()
{
	if (m_lock < 0) {
		PDEBUG << "Not locked yet (" << m_lock << ")" << endl;
		return;
	}

	std::string path = cacheDir();
	PTRACE << "Unlocking file " << path + "/lock" << endl;
	struct flock flck;
	memset(&flck, 0x00, sizeof(struct flock));
	flck.l_type = F_UNLCK;
	if (fcntl(m_lock, F_SETLK, &flck) == -1) {
		throw PEX(str::printf("Unable to unlock cache, please delete %s/lock manually if required", path.c_str()));
	}
	if (::close(m_lock) == -1) {
		throw PEX_ERRNO();
	}
}
Example #14
0
// Allocates a backend of a specific repository type
Backend *Backend::backendForName(const std::string &name, const Options &options)
{
#ifdef USE_SUBVERSION
    if (name == "svn" || name == "subversion") {
        return new SubversionBackend(options);
    }
#endif
#ifdef USE_GIT
    if (name == "git") {
        return new GitBackend(options);
    }
#endif
#ifdef USE_MERCURIAL
    if (name == "hg" || name == "mercurial") {
        return new MercurialBackend(options);
    }
#endif

    throw PEX(std::string("No such backend: " + name));
}
Example #15
0
// Opens the database connection
void LdbCache::opendb()
{
	if (m_db) return;

	std::string path = cacheDir() + "/ldb";
	PDEBUG << "Using cache dir: " << path << endl;
	if (!sys::fs::dirExists(path)) {
		sys::fs::mkpath(path);
	}
	leveldb::Options options;
	options.create_if_missing = false;
	leveldb::Status s = leveldb::DB::Open(options, path, &m_db);
	if (!s.ok()) {
		// New cache: Import revisions from old cache
		options.create_if_missing = true;
		leveldb::Status s = leveldb::DB::Open(options, path, &m_db);
		if (!s.ok()) {
			throw PEX(str::printf("Unable to open database %s: %s", path.c_str(), s.ToString().c_str()));
		}

		Cache c(m_backend, m_opts);
		import(&c);
	}
}
Example #16
0
// Detects Gnuplot terminals, and checks wheter the X11 terminal is available
void Plot::detectTerminals()
{
	if (!s_detectTerminals) { // Run only once
		return;
	}

	std::string terms;
	try {
		// Set dummy pager for terminal listing
		char *oldPager = getenv("PAGER");
		if (oldPager) {
			oldPager = strdup(oldPager);
		}
		setenv("PAGER", "cat", 1);

		int ret;
		std::string path = sys::fs::which("gnuplot");
		terms = sys::io::exec(&ret, path.c_str(), "-e", "set terminal; quit");
		if (ret != 0) {
			throw PEX(terms);
		}

		if (!oldPager) {
			unsetenv("PAGER");
		} else {
			setenv("PAGER", oldPager, 1);
			free(oldPager);
		}
	} catch (const std::exception &ex) {
		Logger::info() << "Can't query list of supported Gnuplot terminals ("
			<< ex.what() << ")" << std::endl;
	}

	s_hasX11Term = (terms.find("x11") != std::string::npos);
	s_detectTerminals = false;
}
Example #17
0
// Static diff parsing function for unified diffs
Diffstat DiffParser::parse(std::istream &in)
{
	static const char marker[] = "===================================================================";

	std::string str, file;
	Diffstat ds;
	Diffstat::Stat stat;
	int chunk[2] = {0, 0};

	while (in.good()) {
		std::getline(in, str);
		if (chunk[0] <= 0 && chunk[1] <= 0 && (!str.compare(0, 4, "--- ") || !str.compare(0, 4, "+++ "))) {
			if (!file.empty() && !stat.empty()) {
				ds.m_stats[file] = stat;
				file = std::string();
			}
			stat = Diffstat::Stat();
			std::vector<std::string> header = str::split(str.substr(4), "\t");
			if (header.empty()) {
				throw PEX(std::string("EMPTY HEADER: ")+str);
			}
			if (header[0] != "/dev/null") {
				file = header[0];
				if (file[0] == '"' && file[file.length()-1] == '"') {
					file = file.substr(1, file.length()-2);
				}
				if (!file.compare(0, 2, "a/") || !file.compare(0, 2, "b/")) {
					file = file.substr(2);
				}
			}
		} else if (!str.compare(0, 2, "@@")) {
			std::vector<std::string> header = str::split(str.substr(2), "@@", true);
			if (header.empty()) {
				throw PEX(std::string("EMPTY HEADER: ")+str);
			}
			std::vector<std::string> ranges = str::split(header[0], " ", true);
			if (ranges.size() < 2 || ranges[0].empty() || ranges[1].empty()) {
				throw PEX(std::string("EMPTY HEADER: ")+str);
			}
			size_t pos;
			if ((pos = ranges[0].find(',')) != std::string::npos) {
				str::str2int(ranges[0].substr(pos+1), &chunk[(ranges[0][0] == '-' ? 0 : 1)]);
			} else {
				chunk[(ranges[0][0] == '-' ? 0 : 1)] = 1;
			}
			if ((pos = ranges[1].find(',')) != std::string::npos) {
				str::str2int(ranges[1].substr(pos+1), &chunk[(ranges[1][0] == '-' ? 0 : 1)]);
			} else {
				chunk[(ranges[1][0] == '-' ? 0 : 1)] = 1;
			}
		} else if (!str.empty() && str[0] == '-') {
			stat.cdel += str.length();
			++stat.ldel;
			--chunk[0];
		} else if (!str.empty() && str[0] == '+') {
			stat.cadd += str.length();
			++stat.ladd;
			--chunk[1];
		} else if (str == marker) {
			chunk[0] = chunk[1] = 0;
		} else if (!str.empty() && str[0] == (char)EOF) {
			// git diff-tree pipe prints EOF after diff data
			break;
		} else {
			if (chunk[0] > 0) --chunk[0];
			if (chunk[1] > 0) --chunk[1];
		}
	}

	if (!file.empty() && !stat.empty()) {
		ds.m_stats[file] = stat;
	}
	return ds;
}