@Override protected boolean isPathRecursable(PathData item) throws IOException { if (item.stat.isDirectory()) { return true; } if (item.stat.isSymlink()) { PathData linkedItem = new PathData(item.fs.resolvePath(item.stat.getSymlink()).toString(), getConf()); if (linkedItem.stat.isDirectory()) { if (getOptions().isFollowLink()) { return true; } if (getOptions().isFollowArgLink() && (getDepth() == 0)) { return true; } } } return false; }
@Override protected void processPath(PathData item) throws IOException { //Should we do case insensitive match? String newOwner = (owner == null || owner.equals(item.stat.getOwner())) ? null : owner; String newGroup = (group == null || group.equals(item.stat.getGroup())) ? null : group; if (newOwner != null || newGroup != null) { try { item.fs.setOwner(item.path, newOwner, newGroup); } catch (IOException e) { LOG.debug("Error changing ownership of " + item, e); throw new IOException( "changing ownership of '" + item + "': " + e.getMessage()); } } }
@Test(timeout = 1000) public void testFailFirst() throws IOException { And and = new And(); PathData pathData = mock(PathData.class); Expression first = mock(Expression.class); when(first.apply(pathData, -1)).thenReturn(Result.FAIL); Expression second = mock(Expression.class); when(second.apply(pathData, -1)).thenReturn(Result.PASS); Deque<Expression> children = new LinkedList<Expression>(); children.add(second); children.add(first); and.addChildren(children); assertEquals(Result.FAIL, and.apply(pathData, -1)); verify(first).apply(pathData, -1); verifyNoMoreInteractions(first); verifyNoMoreInteractions(second); }
@Test(timeout = 1000) public void testFailSecond() throws IOException { And and = new And(); PathData pathData = mock(PathData.class); Expression first = mock(Expression.class); when(first.apply(pathData, -1)).thenReturn(Result.PASS); Expression second = mock(Expression.class); when(second.apply(pathData, -1)).thenReturn(Result.FAIL); Deque<Expression> children = new LinkedList<Expression>(); children.add(second); children.add(first); and.addChildren(children); assertEquals(Result.FAIL, and.apply(pathData, -1)); verify(first).apply(pathData, -1); verify(second).apply(pathData, -1); verifyNoMoreInteractions(first); verifyNoMoreInteractions(second); }
@Test(timeout = 1000) public void testFailBoth() throws IOException { And and = new And(); PathData pathData = mock(PathData.class); Expression first = mock(Expression.class); when(first.apply(pathData, -1)).thenReturn(Result.FAIL); Expression second = mock(Expression.class); when(second.apply(pathData, -1)).thenReturn(Result.FAIL); Deque<Expression> children = new LinkedList<Expression>(); children.add(second); children.add(first); and.addChildren(children); assertEquals(Result.FAIL, and.apply(pathData, -1)); verify(first).apply(pathData, -1); verifyNoMoreInteractions(first); verifyNoMoreInteractions(second); }
@Test(timeout = 1000) public void testStopFirst() throws IOException { And and = new And(); PathData pathData = mock(PathData.class); Expression first = mock(Expression.class); when(first.apply(pathData, -1)).thenReturn(Result.STOP); Expression second = mock(Expression.class); when(second.apply(pathData, -1)).thenReturn(Result.PASS); Deque<Expression> children = new LinkedList<Expression>(); children.add(second); children.add(first); and.addChildren(children); assertEquals(Result.STOP, and.apply(pathData, -1)); verify(first).apply(pathData, -1); verify(second).apply(pathData, -1); verifyNoMoreInteractions(first); verifyNoMoreInteractions(second); }
@Test(timeout = 1000) public void testStopSecond() throws IOException { And and = new And(); PathData pathData = mock(PathData.class); Expression first = mock(Expression.class); when(first.apply(pathData, -1)).thenReturn(Result.PASS); Expression second = mock(Expression.class); when(second.apply(pathData, -1)).thenReturn(Result.STOP); Deque<Expression> children = new LinkedList<Expression>(); children.add(second); children.add(first); and.addChildren(children); assertEquals(Result.STOP, and.apply(pathData, -1)); verify(first).apply(pathData, -1); verify(second).apply(pathData, -1); verifyNoMoreInteractions(first); verifyNoMoreInteractions(second); }
@Test(timeout = 1000) public void testStopFail() throws IOException { And and = new And(); PathData pathData = mock(PathData.class); Expression first = mock(Expression.class); when(first.apply(pathData, -1)).thenReturn(Result.STOP); Expression second = mock(Expression.class); when(second.apply(pathData, -1)).thenReturn(Result.FAIL); Deque<Expression> children = new LinkedList<Expression>(); children.add(second); children.add(first); and.addChildren(children); assertEquals(Result.STOP.combine(Result.FAIL), and.apply(pathData, -1)); verify(first).apply(pathData, -1); verify(second).apply(pathData, -1); verifyNoMoreInteractions(first); verifyNoMoreInteractions(second); }
/** * Tests valid and invalid group arguments to chgrp. */ @Test public void testChgrpGroupValidity() { // This test only covers argument parsing, so override to skip processing. FsCommand chgrp = new FsShellPermissions.Chgrp() { @Override protected void processArgument(PathData item) { } }; chgrp.setConf(new Configuration()); // The following are valid (no exception expected). chgrp.run("group", "/path"); // The following are valid only on Windows. assertValidArgumentsOnWindows(chgrp, "Group With Spaces", "/path"); // The following are invalid (exception expected). assertIllegalArguments(chgrp, ":gr#oup", "/path"); assertIllegalArguments(chgrp, ":gr%oup", "/path"); }
@Test(timeout = 1000) public void testPass() throws IOException { And and = new And(); PathData pathData = mock(PathData.class); Expression first = mock(Expression.class); when(first.apply(pathData, -1)).thenReturn(Result.PASS); Expression second = mock(Expression.class); when(second.apply(pathData, -1)).thenReturn(Result.PASS); Deque<Expression> children = new LinkedList<Expression>(); children.add(second); children.add(first); and.addChildren(children); assertEquals(Result.PASS, and.apply(pathData, -1)); verify(first).apply(pathData, -1); verify(second).apply(pathData, -1); verifyNoMoreInteractions(first); verifyNoMoreInteractions(second); }
/** Returns true if the target is an ancestor of the source. */ private boolean isAncestor(PathData source, PathData target) { for (Path parent = source.path; (parent != null) && !parent.isRoot(); parent = parent.getParent()) { if (parent.equals(target.path)) { return true; } } return false; }
@Override protected void recursePath(PathData item) throws IOException { if (isStop(item)) { // this item returned a stop result so don't recurse any further return; } if (getDepth() >= getOptions().getMaxDepth()) { // reached the maximum depth so don't got any further. return; } if (item.stat.isSymlink() && getOptions().isFollowLink()) { PathData linkedItem = new PathData(item.stat.getSymlink().toString(), getConf()); if (isAncestor(item, linkedItem)) { getOptions().getErr().println( "Infinite loop ignored: " + item.toString() + " -> " + linkedItem.toString()); return; } if (linkedItem.exists) { item = linkedItem; } } if (item.stat.isDirectory()) { super.recursePath(item); } }
@Override protected void processPath(PathData item) throws IOException { if (getOptions().isDepthFirst()) { // depth first so leave until post processing return; } applyItem(item); }
@Override protected void postProcessPath(PathData item) throws IOException { if (!getOptions().isDepthFirst()) { // not depth first so already processed return; } applyItem(item); }
private void applyItem(PathData item) throws IOException { if (getDepth() >= getOptions().getMinDepth()) { Result result = getRootExpression().apply(item, getDepth()); if (Result.STOP.equals(result)) { addStop(item); } } }
@Override protected void processArguments(LinkedList<PathData> args) throws IOException { Expression expr = getRootExpression(); expr.setOptions(getOptions()); expr.prepare(); super.processArguments(args); expr.finish(); }
/** * Returns the {@link FileStatus} from the {@link PathData} item. If the * current options require links to be followed then the returned file status * is that of the linked file. * * @param item * PathData * @param depth * current depth in the process directories * @return FileStatus */ protected FileStatus getFileStatus(PathData item, int depth) throws IOException { FileStatus fileStatus = item.stat; if (fileStatus.isSymlink()) { if (options.isFollowLink() || (options.isFollowArgLink() && (depth == 0))) { Path linkedFile = item.fs.resolvePath(fileStatus.getSymlink()); fileStatus = getFileSystem(item).getFileStatus(linkedFile); } } return fileStatus; }
@Override public Result apply(PathData item, int depth) throws IOException { if (expression != null) { return expression.apply(item, -1); } return Result.PASS; }
@Override public Result apply(PathData item, int depth) throws IOException { String name = getPath(item).getName(); if (!caseSensitive) { name = StringUtils.toLowerCase(name); } if (globPattern.matches(name)) { return Result.PASS; } else { return Result.FAIL; } }
@Override protected void processPath(PathData item) throws IOException { short newperms = pp.applyNewPermission(item.stat); if (item.stat.getPermission().toShort() != newperms) { try { item.fs.setPermission(item.path, new FsPermission(newperms)); } catch (IOException e) { LOG.debug("Error changing permissions of " + item, e); throw new IOException( "changing permissions of '" + item + "': " + e.getMessage()); } } }
@Override protected void processPath(PathData item) throws IOException { System.out.println("processing: "+item); processed++; if (item.stat.isFile()) { System.out.println("throw interrupt"); throw new InterruptedIOException(); } }
@Test(timeout = 1000) public void testPrint() throws IOException { Print.Print0 print = new Print.Print0(); PrintStream out = mock(PrintStream.class); FindOptions options = new FindOptions(); options.setOut(out); print.setOptions(options); String filename = "/one/two/test"; PathData item = new PathData(filename, mockFs.getConf()); assertEquals(Result.PASS, print.apply(item, -1)); verify(out).print(filename + '\0'); verifyNoMoreInteractions(out); }
@Test(timeout = 1000) public void apply() throws IOException { PathData item = mock(PathData.class); when(expr.apply(item, -1)).thenReturn(Result.PASS).thenReturn(Result.FAIL); assertEquals(Result.PASS, test.apply(item, -1)); assertEquals(Result.FAIL, test.apply(item, -1)); verify(expr, times(2)).apply(item, -1); verifyNoMoreInteractions(expr); }
@Test(timeout = 1000) public void testPrint() throws IOException { Print print = new Print(); PrintStream out = mock(PrintStream.class); FindOptions options = new FindOptions(); options.setOut(out); print.setOptions(options); String filename = "/one/two/test"; PathData item = new PathData(filename, mockFs.getConf()); assertEquals(Result.PASS, print.apply(item, -1)); verify(out).print(filename + '\n'); verifyNoMoreInteractions(out); }
private PathData createPathData(String name) throws IOException { Path path = new Path(name); FileStatus fstat = mock(FileStatus.class); when(fstat.getPath()).thenReturn(path); when(fstat.toString()).thenReturn("fileStatus:" + name); when(mockFs.getFileStatus(eq(path))).thenReturn(fstat); PathData item = new PathData(path.toString(), conf); return item; }
/** * Applies child expressions to the {@link PathData} item. If all pass then * returns {@link Result#PASS} else returns the result of the first * non-passing expression. */ @Override public Result apply(PathData item, int depth) throws IOException { Result result = Result.PASS; for (Expression child : getChildren()) { Result childResult = child.apply(item, -1); result = result.combine(childResult); if (!result.isPass()) { return result; } } return result; }