Chris@57
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@57
|
2
|
Chris@57
|
3 /*
|
Chris@57
|
4 EasyMercurial
|
Chris@57
|
5
|
Chris@57
|
6 Based on HgExplorer by Jari Korhonen
|
Chris@57
|
7 Copyright (c) 2010 Jari Korhonen
|
Chris@57
|
8 Copyright (c) 2010 Chris Cannam
|
Chris@57
|
9 Copyright (c) 2010 Queen Mary, University of London
|
Chris@57
|
10
|
Chris@57
|
11 This program is free software; you can redistribute it and/or
|
Chris@57
|
12 modify it under the terms of the GNU General Public License as
|
Chris@57
|
13 published by the Free Software Foundation; either version 2 of the
|
Chris@57
|
14 License, or (at your option) any later version. See the file
|
Chris@57
|
15 COPYING included with this distribution for more information.
|
Chris@57
|
16 */
|
jtkorhonen@0
|
17
|
Chris@62
|
18 #include "common.h"
|
Chris@62
|
19 #include "debug.h"
|
jtkorhonen@0
|
20
|
Chris@62
|
21 #include <QFileInfo>
|
Chris@62
|
22 #include <QProcessEnvironment>
|
Chris@62
|
23 #include <QStringList>
|
Chris@77
|
24 #include <QDir>
|
Chris@172
|
25 #include <QRegExp>
|
jtkorhonen@0
|
26
|
Chris@62
|
27 #include <sys/types.h>
|
Chris@76
|
28
|
Chris@76
|
29 #ifdef Q_OS_WIN32
|
Chris@76
|
30 #define _WIN32_WINNT 0x0500
|
Chris@166
|
31 #define SECURITY_WIN32
|
Chris@76
|
32 #include <windows.h>
|
Chris@76
|
33 #include <security.h>
|
Chris@76
|
34 #else
|
Chris@78
|
35 #include <errno.h>
|
Chris@62
|
36 #include <pwd.h>
|
Chris@78
|
37 #include <unistd.h>
|
Chris@80
|
38 #include <sys/ioctl.h>
|
Chris@80
|
39 #include <sys/types.h>
|
Chris@80
|
40 #include <sys/stat.h>
|
Chris@80
|
41 #include <fcntl.h>
|
Chris@105
|
42 #include <signal.h>
|
Chris@76
|
43 #endif
|
Chris@62
|
44
|
Chris@172
|
45 QString findInPath(QString name, QString installPath, bool executableRequired)
|
Chris@62
|
46 {
|
Chris@77
|
47 bool found = false;
|
Chris@62
|
48 if (name != "") {
|
Chris@172
|
49 if (name[0] != '/'
|
Chris@172
|
50 #ifdef Q_OS_WIN32
|
Chris@178
|
51 && (QRegExp("^\\w:").indexIn(name) != 0)
|
Chris@172
|
52 #endif
|
Chris@178
|
53 ) {
|
Chris@77
|
54 #ifdef Q_OS_WIN32
|
Chris@77
|
55 QChar pathSep = ';';
|
Chris@77
|
56 #else
|
Chris@77
|
57 QChar pathSep = ':';
|
Chris@77
|
58 #endif
|
Chris@62
|
59 name = QFileInfo(name).fileName();
|
Chris@62
|
60 QString path =
|
Chris@62
|
61 QProcessEnvironment::systemEnvironment().value("PATH");
|
Chris@62
|
62 DEBUG << "findExecutable: seeking location for binary " << name
|
Chris@74
|
63 << ": system path is " << path << endl;
|
Chris@172
|
64 if (installPath != "") {
|
Chris@172
|
65 DEBUG << "findExecutable: install path is " << installPath
|
Chris@172
|
66 << ", adding to system path" << endl;
|
Chris@172
|
67 //!!! path = path + pathSep + installPath;
|
Chris@172
|
68 path = installPath + pathSep + path;
|
Chris@172
|
69 }
|
Chris@74
|
70 #ifndef Q_OS_WIN32
|
Chris@178
|
71 //!!!
|
Chris@74
|
72 path = path + ":/usr/local/bin";
|
Chris@74
|
73 DEBUG << "... adding /usr/local/bin just in case (fix and add settings dlg please)"
|
Chris@74
|
74 << endl;
|
Chris@74
|
75 #endif
|
Chris@62
|
76 QStringList elements = path.split(pathSep, QString::SkipEmptyParts);
|
Chris@62
|
77 foreach (QString element, elements) {
|
Chris@77
|
78 QString full = QDir(element).filePath(name);
|
Chris@62
|
79 QFileInfo fi(full);
|
Chris@172
|
80 DEBUG << "findExecutable: looking at " << full << endl;
|
Chris@172
|
81 if (fi.exists() && fi.isFile()) {
|
Chris@172
|
82 DEBUG << "findExecutable: it's a file" << endl;
|
Chris@172
|
83 if (!executableRequired || fi.isExecutable()) {
|
Chris@172
|
84 name = full;
|
Chris@172
|
85 DEBUG << "findExecutable: found at " << name << endl;
|
Chris@172
|
86 found = true;
|
Chris@172
|
87 break;
|
Chris@172
|
88 }
|
Chris@62
|
89 }
|
Chris@62
|
90 }
|
Chris@62
|
91 }
|
Chris@62
|
92 }
|
Chris@77
|
93 #ifdef Q_OS_WIN32
|
Chris@77
|
94 if (!found) {
|
Chris@77
|
95 if (!name.endsWith(".exe")) {
|
Chris@172
|
96 return findInPath(name + ".exe", installPath, executableRequired);
|
Chris@77
|
97 }
|
Chris@77
|
98 }
|
Chris@77
|
99 #endif
|
Chris@62
|
100 return name;
|
Chris@62
|
101 }
|
jtkorhonen@0
|
102
|
Chris@62
|
103 #ifdef Q_OS_WIN32
|
Chris@62
|
104 QString getUserRealName()
|
Chris@62
|
105 {
|
Chris@76
|
106 TCHAR buf[1024];
|
Chris@76
|
107 long unsigned int maxlen = 1000;
|
Chris@62
|
108 LPTSTR info = buf;
|
jtkorhonen@0
|
109
|
Chris@76
|
110 if (!GetUserNameEx(NameDisplay, info, &maxlen)) {
|
Chris@76
|
111 DEBUG << "GetUserNameEx failed: " << GetLastError() << endl;
|
Chris@62
|
112 return "";
|
Chris@62
|
113 }
|
jtkorhonen@0
|
114
|
Chris@76
|
115 #ifdef UNICODE
|
Chris@76
|
116 return QString::fromUtf16((const unsigned short *)info);
|
Chris@76
|
117 #else
|
Chris@76
|
118 return QString::fromLocal8Bit(info);
|
Chris@76
|
119 #endif
|
Chris@62
|
120 }
|
luisf@71
|
121 #else
|
luisf@71
|
122 #ifdef Q_OS_MAC
|
Chris@62
|
123 // Nothing here: definition is in common_osx.mm
|
Chris@62
|
124 #else
|
Chris@62
|
125 QString getUserRealName()
|
Chris@62
|
126 {
|
Chris@62
|
127 const int maxlen = 1023;
|
Chris@62
|
128 char buf[maxlen + 2];
|
jtkorhonen@0
|
129
|
Chris@62
|
130 if (getlogin_r(buf, maxlen)) return "";
|
jtkorhonen@0
|
131
|
Chris@62
|
132 struct passwd *p = getpwnam(buf);
|
Chris@62
|
133 if (!p) return "";
|
Chris@62
|
134
|
Chris@62
|
135 QString s(p->pw_gecos);
|
Chris@62
|
136 if (s != "") s = s.split(',')[0];
|
Chris@62
|
137 return s;
|
Chris@62
|
138 }
|
Chris@62
|
139 #endif
|
luisf@71
|
140 #endif
|
jtkorhonen@0
|
141
|
Chris@78
|
142 void loseControllingTerminal()
|
Chris@78
|
143 {
|
Chris@78
|
144 #ifndef Q_OS_WIN32
|
Chris@80
|
145
|
Chris@80
|
146 if (!isatty(0)) {
|
Chris@80
|
147 DEBUG << "stdin is not a terminal" << endl;
|
Chris@80
|
148 } else {
|
Chris@80
|
149 DEBUG << "stdin is a terminal, detaching from it" << endl;
|
Chris@80
|
150 if (ioctl(0, TIOCNOTTY, NULL) < 0) {
|
Chris@80
|
151 perror("ioctl failed");
|
Chris@83
|
152 DEBUG << "ioctl for TIOCNOTTY on stdin failed (errno = " << errno << ")" << endl;
|
Chris@78
|
153 } else {
|
Chris@83
|
154 DEBUG << "ioctl for TIOCNOTTY on stdin succeeded" << endl;
|
Chris@83
|
155 return;
|
Chris@78
|
156 }
|
Chris@80
|
157 }
|
Chris@80
|
158
|
Chris@80
|
159 int ttyfd = open("/dev/tty", O_RDWR);
|
Chris@80
|
160 if (ttyfd < 0) {
|
Chris@80
|
161 DEBUG << "failed to open controlling terminal" << endl;
|
Chris@80
|
162 } else {
|
Chris@80
|
163 if (ioctl(ttyfd, TIOCNOTTY, NULL) < 0) {
|
Chris@80
|
164 perror("ioctl failed");
|
Chris@83
|
165 DEBUG << "ioctl for TIOCNOTTY on controlling terminal failed (errno = " << errno << ")" << endl;
|
Chris@80
|
166 } else {
|
Chris@83
|
167 DEBUG << "ioctl for TIOCNOTTY on controlling terminal succeeded" << endl;
|
Chris@83
|
168 return;
|
Chris@78
|
169 }
|
Chris@78
|
170 }
|
Chris@80
|
171
|
Chris@78
|
172 #endif
|
Chris@78
|
173 }
|
Chris@79
|
174
|
Chris@105
|
175 void installSignalHandlers()
|
Chris@105
|
176 {
|
Chris@105
|
177 #ifndef Q_OS_WIN32
|
Chris@105
|
178 sigset_t sgnals;
|
Chris@105
|
179 sigemptyset (&sgnals);
|
Chris@105
|
180 sigaddset(&sgnals, SIGHUP);
|
Chris@105
|
181 sigaddset(&sgnals, SIGCONT);
|
Chris@105
|
182 pthread_sigmask(SIG_BLOCK, &sgnals, 0);
|
Chris@105
|
183 #endif
|
Chris@105
|
184 }
|
Chris@105
|
185
|
Chris@79
|
186 FolderStatus getFolderStatus(QString path)
|
Chris@79
|
187 {
|
Chris@85
|
188 if (path != "/" && path.endsWith("/")) {
|
Chris@85
|
189 path = path.left(path.length()-1);
|
Chris@85
|
190 }
|
Chris@84
|
191 DEBUG << "getFolderStatus: " << path << endl;
|
Chris@79
|
192 QFileInfo fi(path);
|
Chris@79
|
193 if (fi.exists()) {
|
Chris@84
|
194 DEBUG << "exists" << endl;
|
Chris@79
|
195 QDir dir(path);
|
Chris@79
|
196 if (!dir.exists()) { // returns false for files
|
Chris@84
|
197 DEBUG << "not directory" << endl;
|
Chris@79
|
198 return FolderIsFile;
|
Chris@79
|
199 }
|
Chris@79
|
200 if (QDir(dir.filePath(".hg")).exists()) {
|
Chris@84
|
201 DEBUG << "has repo" << endl;
|
Chris@79
|
202 return FolderHasRepo;
|
Chris@79
|
203 }
|
Chris@79
|
204 return FolderExists;
|
Chris@79
|
205 } else {
|
Chris@79
|
206 QDir parent = fi.dir();
|
Chris@79
|
207 if (parent.exists()) {
|
Chris@84
|
208 DEBUG << "parent exists" << endl;
|
Chris@79
|
209 return FolderParentExists;
|
Chris@79
|
210 }
|
Chris@79
|
211 return FolderUnknown;
|
Chris@79
|
212 }
|
Chris@79
|
213 }
|
Chris@79
|
214
|
Chris@79
|
215 QString getContainingRepoFolder(QString path)
|
Chris@79
|
216 {
|
Chris@79
|
217 if (getFolderStatus(path) == FolderHasRepo) return "";
|
Chris@79
|
218
|
Chris@79
|
219 QFileInfo me(path);
|
Chris@79
|
220 QFileInfo parent(me.dir().absolutePath());
|
Chris@79
|
221
|
Chris@79
|
222 while (me != parent) {
|
Chris@79
|
223 QString parentPath = parent.filePath();
|
Chris@79
|
224 if (getFolderStatus(parentPath) == FolderHasRepo) {
|
Chris@79
|
225 return parentPath;
|
Chris@79
|
226 }
|
Chris@79
|
227 me = parent;
|
Chris@79
|
228 parent = me.dir().absolutePath();
|
Chris@79
|
229 }
|
Chris@79
|
230
|
Chris@79
|
231 return "";
|
Chris@79
|
232 }
|
Chris@79
|
233
|
Chris@79
|
234 QString xmlEncode(QString s)
|
Chris@79
|
235 {
|
Chris@79
|
236 s
|
Chris@79
|
237 .replace("&", "&")
|
Chris@79
|
238 .replace("<", "<")
|
Chris@79
|
239 .replace(">", ">")
|
Chris@79
|
240 .replace("\"", """)
|
Chris@79
|
241 .replace("'", "'");
|
Chris@79
|
242
|
Chris@79
|
243 return s;
|
Chris@79
|
244 }
|