Skip to content

Commit 790b81a

Browse files
authored
Add copy-option to merge the source into the target (#65)
Commits: * Add option to copy to merge source with target * Added mergeFolders param to other copy methods * Added missing import * Wrapped lines and improved test name * Added a test case for a merge copy * Documented new mergeFolders option Pull request: #65
1 parent 604f328 commit 790b81a

File tree

4 files changed

+54
-14
lines changed

4 files changed

+54
-14
lines changed

os/src/FileOps.scala

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
package os
88

9+
import java.nio.file
910
import java.nio.file.{Path => _, _}
1011
import java.nio.file.attribute.{FileAttribute, PosixFilePermission, PosixFilePermissions}
1112

@@ -134,28 +135,34 @@ object copy {
134135
def matching(followLinks: Boolean = true,
135136
replaceExisting: Boolean = false,
136137
copyAttributes: Boolean = false,
137-
createFolders: Boolean = false)
138+
createFolders: Boolean = false,
139+
mergeFolders: Boolean = false)
138140
(partialFunction: PartialFunction[Path, Path]): PartialFunction[Path, Unit] = {
139141
new PartialFunction[Path, Unit] {
140142
def isDefinedAt(x: Path) = partialFunction.isDefinedAt(x)
141143
def apply(from: Path) = {
142144
val dest = partialFunction(from)
143145
makeDir.all(dest/up)
144-
os.copy(from, dest, followLinks, replaceExisting, copyAttributes, createFolders)
146+
os.copy(
147+
from, dest, followLinks, replaceExisting, copyAttributes, createFolders, mergeFolders
148+
)
145149
}
146150
}
147151

148152
}
149153
def matching(partialFunction: PartialFunction[Path, Path]): PartialFunction[Path, Unit] = {
150154
matching()(partialFunction)
151155
}
152-
def apply(from: Path,
153-
to: Path,
154-
followLinks: Boolean = true,
155-
replaceExisting: Boolean = false,
156-
copyAttributes: Boolean = false,
157-
createFolders: Boolean = false): Unit = {
158-
if (createFolders) makeDir.all(to/up)
156+
def apply(
157+
from: Path,
158+
to: Path,
159+
followLinks: Boolean = true,
160+
replaceExisting: Boolean = false,
161+
copyAttributes: Boolean = false,
162+
createFolders: Boolean = false,
163+
mergeFolders: Boolean = false
164+
): Unit = {
165+
if (createFolders) makeDir.all(to / up)
159166
val opts1 =
160167
if (followLinks) Array[CopyOption]()
161168
else Array[CopyOption](LinkOption.NOFOLLOW_LINKS)
@@ -169,8 +176,15 @@ object copy {
169176
!to.startsWith(from),
170177
s"Can't copy a directory into itself: $to is inside $from"
171178
)
172-
def copyOne(p: Path) = {
173-
Files.copy(p.wrapped, (to/(p relativeTo from)).wrapped, opts1 ++ opts2 ++ opts3:_*)
179+
180+
def copyOne(p: Path): file.Path = {
181+
val target = to / p.relativeTo(from)
182+
if (mergeFolders && isDir(p, followLinks) && isDir(target, followLinks)) {
183+
// nothing to do
184+
target.wrapped
185+
} else {
186+
Files.copy(p.wrapped, target.wrapped, opts1 ++ opts2 ++ opts3: _*)
187+
}
174188
}
175189

176190
copyOne(from)
@@ -187,8 +201,12 @@ object copy {
187201
followLinks: Boolean = true,
188202
replaceExisting: Boolean = false,
189203
copyAttributes: Boolean = false,
190-
createFolders: Boolean = false): Unit = {
191-
os.copy(from, to/from.last, followLinks, replaceExisting, copyAttributes, createFolders)
204+
createFolders: Boolean = false,
205+
mergeFolders: Boolean = false): Unit = {
206+
os.copy(
207+
from, to/from.last,
208+
followLinks, replaceExisting, copyAttributes, createFolders, mergeFolders
209+
)
192210
}
193211
}
194212

os/test/src-jvm/ExampleTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ object ExampleTests extends TestSuite{
254254
assert(lines == 9)
255255
}
256256

257-
test("noLongLines"){
257+
test("Source code line length does not exceed 100"){
258258

259259
// Ensure that we don't have any Scala files in the current working directory
260260
// which have lines more than 100 characters long, excluding generated sources

os/test/src-jvm/OpTestsJvmOnly.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ object OpTestsJvmOnly extends TestSuite{
102102
os.copy(d/"folderA", d/"folderC")
103103
assert(os.read(d/"folderC"/"folderB"/"file") == "Cow")
104104
}
105+
test("merging"){
106+
val mergeDir = d/"merge"
107+
os.write(mergeDir/"folderA"/"folderB"/"file", "Cow", createFolders = true)
108+
os.write(mergeDir/"folderC"/"file", "moo", createFolders = true)
109+
os.copy(mergeDir/"folderA", mergeDir/"folderC", mergeFolders = true)
110+
assert(os.read(mergeDir/"folderC"/"folderB"/"file") == "Cow")
111+
assert(os.read(mergeDir/"folderC"/"file") == "moo")
112+
}
105113
}
106114
test("mv"){
107115
test("basic"){

readme.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,20 @@ os.list(wd / "folder2") ==> Seq(wd / "folder2" / "nestedA", wd / "folder2" / "ne
924924
os.copy.over(wd / "folder1", wd / "folder2")
925925
os.list(wd / "folder2") ==> Seq(wd / "folder2" / "one.txt")
926926
```
927+
928+
#### os.copy with `mergeFolders`
929+
930+
If you want to copy a directory over another but don't want to overwrite the whole destination directory (and loose it's content),
931+
you can use the `mergeFolders` option of [os.copy](#oscopy).
932+
933+
```scala
934+
os.list(wd / "folder1") ==> Seq(wd / "folder1" / "one.txt")
935+
os.list(wd / "folder2") ==> Seq(wd / "folder2" / "nestedA", wd / "folder2" / "nestedB")
936+
os.copy(wd / "folder1", wd / "folder2", mergeFolders = true)
937+
os.list(wd / "folder2") ==> Seq(wd / "folder2" / "one.txt", wd / "folder2" / "nestedA", wd / "folder2" / "nestedB")
938+
```
939+
940+
927941
#### os.makeDir
928942

929943
```scala

0 commit comments

Comments
 (0)