comparison src/org/tmatesoft/hg/util/RegularFileStats.java @ 713:661e77dc88ba tip

Mac support: respect Mac alternatives of command-line arguments for common unix tools
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Sun, 03 Aug 2014 18:09:00 +0200
parents c02b5710d9ac
children
comparison
equal deleted inserted replaced
712:a864fb309e4b 713:661e77dc88ba
66 private Map<String, Set<String>> dir2execs = new TreeMap<String, Set<String>>(); 66 private Map<String, Set<String>> dir2execs = new TreeMap<String, Set<String>>();
67 67
68 68
69 RegularFileStats(SessionContext ctx) { 69 RegularFileStats(SessionContext ctx) {
70 sessionContext = ctx; 70 sessionContext = ctx;
71 final Pattern pLink, pExec;
71 if (Internals.runningOnWindows()) { 72 if (Internals.runningOnWindows()) {
72 // XXX this implementation is not yet tested against any Windows repository, 73 // XXX this implementation is not yet tested against any Windows repository,
73 // only against sample dir listings. As long as Mercurial doesn't handle Windows 74 // only against sample dir listings. As long as Mercurial doesn't handle Windows
74 // links, we don't really need this 75 // links, we don't really need this
75 command = Arrays.asList("cmd", "/c", "dir"); 76 command = Arrays.asList("cmd", "/c", "dir");
76 // Windows patterns need to work against full directory listing (I didn't find a way 77 // Windows patterns need to work against full directory listing (I didn't find a way
77 // to list single file with its attributes like SYMLINK) 78 // to list single file with its attributes like SYMLINK)
78 Pattern pLink = Pattern.compile("^\\S+.*\\s+<SYMLINK>\\s+(\\S.*)\\s+\\[(.+)\\]$", Pattern.MULTILINE); 79 pLink = Pattern.compile("^\\S+.*\\s+<SYMLINK>\\s+(\\S.*)\\s+\\[(.+)\\]$", Pattern.MULTILINE);
79 Pattern pExec = Pattern.compile("^\\S+.*\\s+\\d+\\s+(\\S.*\\.exe)$", Pattern.MULTILINE); 80 pExec = Pattern.compile("^\\S+.*\\s+\\d+\\s+(\\S.*\\.exe)$", Pattern.MULTILINE);
80 linkMatcher = pLink.matcher(""); 81 } else if (Internals.runningOnMac()) {
81 execMatcher = pExec.matcher(""); 82 command = Arrays.asList("/bin/ls", "-lnoT");
83 // -n to present userid and group as digits
84 // -o don't need group
85 // -T complete time in standard format (used as boundary in the pattern)
86 // Perhaps, shall use -B for octal non-printable characters. Shall implement unescapeFilename, below, then.
87 pLink = Pattern.compile("^lrwxr.xr.x\\s.*\\s\\d\\d:\\d\\d:\\d\\d \\d\\d\\d\\d (.+) -> (.+)$", Pattern.MULTILINE);
88 pExec = Pattern.compile("^-..[sx]..[sx]..[sx]\\s.*\\s\\d\\d:\\d\\d:\\d\\d \\d\\d\\d\\d (.+)$", Pattern.MULTILINE);
82 } else { 89 } else {
83 command = Arrays.asList("/bin/ls", "-l", "-Q"); // -Q is essential to get quoted name - the only way to 90 command = Arrays.asList("/bin/ls", "-l", "-Q"); // -Q is essential to get quoted name - the only way to
84 // tell exact file name (which may start or end with spaces. 91 // tell exact file name (which may start or end with spaces.
85 Pattern pLink = Pattern.compile("^lrwxrwxrwx\\s.*\\s\"(.*)\"\\s+->\\s+\"(.*)\"$", Pattern.MULTILINE); 92 pLink = Pattern.compile("^lrwxrwxrwx\\s.*\\s\"(.*)\"\\s+->\\s+\"(.*)\"$", Pattern.MULTILINE);
86 // pLink: group(1) is full name if single file listing (ls -l /usr/bin/java) and short name if directory listing (ls -l /usr/bin) 93 // pLink: group(1) is full name if single file listing (ls -l /usr/bin/java) and short name if directory listing (ls -l /usr/bin)
87 // group(2) is link target 94 // group(2) is link target
88 Pattern pExec = Pattern.compile("^-..[sx]..[sx]..[sx]\\s.*\\s\"(.+)\"$", Pattern.MULTILINE); 95 pExec = Pattern.compile("^-..[sx]..[sx]..[sx]\\s.*\\s\"(.+)\"$", Pattern.MULTILINE);
89 // pExec: group(1) is name of executable file 96 // pExec: group(1) is name of executable file
90 linkMatcher = pLink.matcher("");
91 execMatcher = pExec.matcher("");
92 } 97 }
98 linkMatcher = pLink.matcher("");
99 execMatcher = pExec.matcher("");
93 execHelper = new ProcessExecHelper(); 100 execHelper = new ProcessExecHelper();
94 } 101 }
95 102
96 /** 103 /**
97 * Fails silently indicating false for both x and l in case interaction with file system failed 104 * Fails silently indicating false for both x and l in case interaction with file system failed
117 CharSequence result = execHelper.exec(cmd); 124 CharSequence result = execHelper.exec(cmd);
118 125
119 if (execMatcher.reset(result).find()) { 126 if (execMatcher.reset(result).find()) {
120 execs = new HashSet<String>(); 127 execs = new HashSet<String>();
121 do { 128 do {
122 execs.add(execMatcher.group(1)); 129 execs.add(unescapeFilename(execMatcher.group(1)));
123 } while (execMatcher.find()); 130 } while (execMatcher.find());
124 } else { 131 } else {
125 execs = Collections.emptySet(); // indicate we tried and found nothing 132 execs = Collections.emptySet(); // indicate we tried and found nothing
126 } 133 }
127 if (linkMatcher.reset(result).find()) { 134 if (linkMatcher.reset(result).find()) {
128 links = new HashMap<String, String>(); 135 links = new HashMap<String, String>();
129 do { 136 do {
130 links.put(linkMatcher.group(1), linkMatcher.group(2)); 137 links.put(unescapeFilename(linkMatcher.group(1)), unescapeFilename(linkMatcher.group(2)));
131 } while (linkMatcher.find()); 138 } while (linkMatcher.find());
132 } else { 139 } else {
133 links = Collections.emptyMap(); 140 links = Collections.emptyMap();
134 } 141 }
135 dir2links.put(dirName, links); 142 dir2links.put(dirName, links);
148 // IGNORE, keep isExec and isSymlink false 155 // IGNORE, keep isExec and isSymlink false
149 } catch (IOException ex) { 156 } catch (IOException ex) {
150 sessionContext.getLog().dump(getClass(), Warn, ex, String.format("Failed to detect flags for %s", f)); 157 sessionContext.getLog().dump(getClass(), Warn, ex, String.format("Failed to detect flags for %s", f));
151 // IGNORE, keep isExec and isSymlink false 158 // IGNORE, keep isExec and isSymlink false
152 } 159 }
153 } 160 }
154 161
155 public boolean isExecutable() { 162 public boolean isExecutable() {
156 return isExec; 163 return isExec;
157 } 164 }
158 165
164 if (isSymlink) { 171 if (isSymlink) {
165 return symlinkValue; 172 return symlinkValue;
166 } 173 }
167 throw new UnsupportedOperationException(); 174 throw new UnsupportedOperationException();
168 } 175 }
176
177 // FIXME nop at the moment, but need to implement if use escape code for non-printable characters
178 private static String unescapeFilename(String cs) {
179 return cs;
180 }
169 } 181 }