1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.buildcache.its;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.LinkOption;
25 import java.nio.file.Path;
26 import java.nio.file.attribute.FileTime;
27 import java.nio.file.attribute.PosixFilePermission;
28 import java.nio.file.attribute.PosixFilePermissions;
29 import java.time.Instant;
30 import java.time.ZoneId;
31 import java.time.ZonedDateTime;
32 import java.time.format.DateTimeFormatter;
33 import java.util.EnumSet;
34 import java.util.Map;
35 import java.util.Objects;
36 import java.util.Set;
37 import java.util.TreeMap;
38
39 public class PathEntry implements Comparable<PathEntry> {
40
41 private final Path abs;
42 private final Path path;
43 private final Map<String, Object> attributes;
44
45 public PathEntry(Path abs, Path root) {
46 this.abs = abs;
47 this.path = abs.startsWith(root) ? root.relativize(abs) : abs;
48 this.attributes = readAttributes(abs);
49 }
50
51 @Override
52 public int compareTo(PathEntry o) {
53 return path.toString().compareTo(o.path.toString());
54 }
55
56 boolean isNotDirectory() {
57 return is("isRegularFile") || is("isSymbolicLink") || is("isOther");
58 }
59
60 boolean isDirectory() {
61 return is("isDirectory");
62 }
63
64 private boolean is(String attr) {
65 Object d = attributes.get(attr);
66 return d instanceof Boolean && (Boolean) d;
67 }
68
69 String display() {
70 String suffix;
71 String link = "";
72 if (is("isSymbolicLink")) {
73 suffix = "@";
74 try {
75 Path l = Files.readSymbolicLink(abs);
76 link = " -> " + l.toString();
77 } catch (IOException e) {
78
79 }
80 } else if (is("isDirectory")) {
81 suffix = "/";
82 } else if (is("isExecutable")) {
83 suffix = "*";
84 } else if (is("isOther")) {
85 suffix = "";
86 } else {
87 suffix = "";
88 }
89 return path.toString() + suffix + link;
90 }
91
92 String longDisplay() {
93 String username = getUsername();
94 String group = getGroup();
95 Number length = (Number) attributes.get("size");
96 if (length == null) {
97 length = 0L;
98 }
99 String lengthString = formatLength(length);
100 @SuppressWarnings("unchecked")
101 Set<PosixFilePermission> perms = (Set<PosixFilePermission>) attributes.get("permissions");
102 if (perms == null) {
103 perms = EnumSet.noneOf(PosixFilePermission.class);
104 }
105 return (is("isDirectory") ? "d" : (is("isSymbolicLink") ? "l" : (is("isOther") ? "o" : "-")))
106 + PosixFilePermissions.toString(perms) + " "
107 + String.format(
108 "%3s",
109 (attributes.containsKey("nlink")
110 ? attributes.get("nlink").toString()
111 : "1"))
112 + " " + username + " " + group + " " + lengthString + " "
113 + toString((FileTime) attributes.get("lastModifiedTime"))
114 + " " + display();
115 }
116
117 private String getUsername() {
118 String username = attributes.containsKey("owner") ? Objects.toString(attributes.get("owner"), null) : "owner";
119 if (username.length() > 8) {
120 username = username.substring(0, 8);
121 } else {
122 username = String.format("%-8s", username);
123 }
124 return username;
125 }
126
127 private String getGroup() {
128 String group = attributes.containsKey("group") ? Objects.toString(attributes.get("group"), null) : "group";
129 if (group.length() > 8) {
130 group = group.substring(0, 8);
131 } else {
132 group = String.format("%-8s", group);
133 }
134 return group;
135 }
136
137 private String formatLength(Number length) {
138 double l = length.longValue();
139 String unit = "B";
140 if (l >= 1000) {
141 l /= 1024;
142 unit = "K";
143 if (l >= 1000) {
144 l /= 1024;
145 unit = "M";
146 if (l >= 1000) {
147 l /= 1024;
148 unit = "T";
149 }
150 }
151 }
152 if (l < 10 && length.longValue() > 1000) {
153 return String.format("%.1f%s", l, unit);
154 } else {
155 return String.format("%3.0f%s", l, unit);
156 }
157 }
158
159 protected String toString(FileTime time) {
160 long millis = (time != null) ? time.toMillis() : -1L;
161 if (millis < 0L) {
162 return "------------";
163 }
164 ZonedDateTime dt = Instant.ofEpochMilli(millis).atZone(ZoneId.systemDefault());
165 if (System.currentTimeMillis() - millis < 183L * 24L * 60L * 60L * 1000L) {
166 return DateTimeFormatter.ofPattern("MMM ppd HH:mm").format(dt);
167 } else {
168 return DateTimeFormatter.ofPattern("MMM ppd yyyy").format(dt);
169 }
170 }
171
172 protected Map<String, Object> readAttributes(Path path) {
173 Map<String, Object> attrs = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
174 for (String view : path.getFileSystem().supportedFileAttributeViews()) {
175 try {
176 Map<String, Object> ta = Files.readAttributes(path, view + ":*", LinkOption.NOFOLLOW_LINKS);
177 ta.forEach(attrs::putIfAbsent);
178 } catch (IOException e) {
179
180 }
181 }
182 attrs.computeIfAbsent("isExecutable", s -> Files.isExecutable(path));
183 attrs.computeIfAbsent("permissions", s -> getPermissionsFromFile(path.toFile()));
184 return attrs;
185 }
186
187 static Set<PosixFilePermission> getPermissionsFromFile(File f) {
188 Set<PosixFilePermission> perms = EnumSet.noneOf(PosixFilePermission.class);
189 if (f.canRead()) {
190 perms.add(PosixFilePermission.OWNER_READ);
191 perms.add(PosixFilePermission.GROUP_READ);
192 perms.add(PosixFilePermission.OTHERS_READ);
193 }
194 if (f.canWrite()) {
195 perms.add(PosixFilePermission.OWNER_WRITE);
196 perms.add(PosixFilePermission.GROUP_WRITE);
197 perms.add(PosixFilePermission.OTHERS_WRITE);
198 }
199 if (f.canExecute()) {
200 perms.add(PosixFilePermission.OWNER_EXECUTE);
201 perms.add(PosixFilePermission.GROUP_EXECUTE);
202 perms.add(PosixFilePermission.OTHERS_EXECUTE);
203 }
204 return perms;
205 }
206 }