Find first occurrence of a file name in project in Kotlin - loops

I'd like to be able to search for "someFileName" file in a project that may contain more than one, starting at the root directory, and then stopping when I encounter the first one. Something like a FileTreeWalk that exits early based on some condition.

fun main() {
val found = File("${yourProjDir}").walk().find { it.name == "${fileNameToFind}" }
println(found?.name)
}

Related

How to read a text file from resources without javaClass

I need to read a text file with readLines() and I've already found this question, but the code in the answers always uses some variation of javaClass; it seems to work only inside a class, while I'm using just a simple Kotlin file with no declared classes. Writing it like this is correct syntax-wise but it looks really ugly and it always returns null, so it must be wrong:
val lines = object {}.javaClass.getResource("file.txt")?.toURI()?.toPath()?.readLines()
Of course I could just specify the raw path like this, but I wonder if there's a better way:
val lines = File("src/main/resources/file.txt").readLines()
Thanks to this answer for providing the correct way to read the file. Currently, reading files from resources without using javaClass or similar constructs doesn't seem to be possible.
// use this if you're inside a class
val lines = this::class.java.getResourceAsStream("file.txt")?.bufferedReader()?.readLines()
// use this otherwise
val lines = object {}.javaClass.getResourceAsStream("file.txt")?.bufferedReader()?.readLines()
According to other similar questions I've found, the second way might also work within a lambda but I haven't tested it. Notice the need for the ?. operator and the lines?.let {} syntax needed from this point onward, because getResourceAsStream() returns null if no resource is found with the given name.
Kotlin doesn't have its own means of getting a resource, so you have to use Java's method Class.getResource. You should not assume that the resource is a file (i.e. don't use toPath) as it could well be an entry in a jar, and not a file on the file system. To read a resource, it is easier to get the resource as an InputStream and then read lines from it:
val lines = this::class.java.getResourceAsStream("file.txt").bufferedReader().readLines()
I'm not sure if my response attempts to answer your exact question, but perhaps you could do something like this:
I'm guessing in the final use case, the file names would be dynamic - Not statically declared. In which case, if you have access to or know the path to the folder, you could do something like this:
// Create an extension function on the String class to retrieve a list of
// files available within a folder. Though I have not added a check here
// to validate this, a condition can be added to assert if the extension
// called is executed on a folder or not
fun String.getFilesInFolder(): Array<out File>? = with(File(this)) { return listFiles() }
// Call the extension function on the String folder path wherever required
fun retrieveFiles(): Array<out File>? = [PATH TO FOLDER].getFilesInFolder()
Once you have a reference to the List<out File> object, you could do something like this:
// Create an extension function to read
fun File.retrieveContent() = readLines()
// You can can further expand this use case to conditionally return
// readLines() or entire file data using a buffered reader or convert file
// content to a Data class through GSON/whatever.
// You can use Generic Constraints
// Refer this article for possibilities
// https://kotlinlang.org/docs/generics.html#generic-constraints
// Then simply call this extension function after retrieving files in the folder.
listOfFiles?.forEach { singleFile -> println(singleFile.retrieveContent()) }
In order to have the same url that work for both Jar or in local, the url (or path) needs to be a relative path from the repository root.
..meaning, the location of your file or folder from your src folder.
could be "/main/resources/your-folder/" or "/client/notes/somefile.md"
The url must be a relative path from the repository root.
it must be "src/main/resources/your-folder/" or "src/client/notes/somefile.md"
Now you get the drill, and luckily for Intellij Idea users, you can get the correct path with a right-click on the folder or file -> copy Path/Reference.. -> Path From Repository Root (this is it)
Last, paste it and do your thing.

How to create and loop over an ArrayList of strings in Jenkins Groovy Pipeline

As stated in the title, I'm attempting to loop over an ArrayList of strings in a Jenkins Groovy Pipeline script (using scripted Pipeline syntax). Let me lay out the entire "problem" for you.
I start with a string of filesystem locations separated by spaces: "/var/x /var/y /var/z ... " like so. I loop over this string adding each character to a temp string. And then when I reach a space, I add that temp string to the array and restart. Here's some code showing how I do this:
def full_string = "/var/x /var/y /var/z"
def temp = ""
def arr = [] as ArrayList
full_string.each {
if ( "$it" == " " ) {
arr.add("$temp") <---- have also tried ( arr << "$temp" )
temp = ""
} else {
temp = "$temp" + "$it"
}
}
// if statement to catch last element
See, the problem with this is that if I later go to loop over the array it decides to loop over every individual char instead of the entire /var/x string like I want it to.
I'm new to Groovy so I've been learning as I build this pipeline. Using Jenkins version 2.190.1 if that helps at all. I've looked around on SO and Groovy docs, as well as the pipeline syntax docs on Jenkins. Can't seem to find what I've been looking for. I'm sure that my solution is not the most elegant or efficient, but I will settle for understanding how it works first before trying to squeeze the most performance out of it.
I found this question but this was similarly unhelpful: Dynamically adding elements to ArrayList in Groovy.
Edit: I'm trying to translate old company c-shell build scripts into Jenkins Pipelines. My initial string is an environment variable available on all our nodes that I also need to have available inside the Pipeline.
TL;DR - I need to be able to create an array from space separated values in a string, and then be able to loop over said array and each "element" be a complete string instead of a single char so that I can run pipeline steps properly.
Try running this in your Jenkins script console (your.jenkins.url.yourcompany.com/script):
def full_string = "/var/x /var/y /var/z"
def arr = full_string.split(" ")
for (i in arr) {
println "now got ${i}"
}
Result:
now got /var/x
now got /var/y
now got /var/z

Check whether file exists in server with partial name

I want to search for a file, say with name having the date time stamp (DDMMYYYYhhmmss)(14122017143339). But in the server possibilities are there that the filename which I am expecting can be like either (14122017143337 OR 14122017143338 OR 14122017143339 OR 14122017143340) as there is a minute change in the seconds.
Now, I am trying to search for the file with only a portion of its name say like (DDMMYYYYhhmm)only uptil the minute. Meaning the file which i am expecting should contain the string (141220171433) in its name.
Can someone help on how can we achieve this Using Java?
Note - Am using Selenium for my coding purposes.
Below code in in Java and will find all files in a folder. you can search for required file name to match
File[] allFiles = new File("FOlder path").listFiles();
for (File f : allFiles)
{
if (f.isFile())
{
if(file.getName().contains("DDMMYYYYhhmm"))
{
System.out.println("true and file found");
// do something here
}
}
}

Creating an Array from the Contents of a Large Folder Quickly

I'm trying to create a workflow that uses an array from a specific folder's contents, however the folder has over 150k contents and thus the process is extremely slow, I am currently using the Dir.entries method to create the array, but need to drastically decrease the time it takes.
Here is my current code:
Dir.entries('directory/to/search')
It simple and straightforward, but not very fast.
If you just want to find the the names of all directories + files under a specified path you can use unix level commands like:
path = 'directory/to/search'
`ls #{path}`.split("\n")
There are way faster:
# . directory has 30 entries in this example
Benchmark.measure { Dir.entries('.') }
=> #<Benchmark::Tms:0x007fe6ab92aee8 #label="", #real=7.675203960388899e-05, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.0, #total=0.0>
Benchmark.measure { `ls`.split("\n") }
=> #<Benchmark::Tms:0x007fe6ab8f9a50 #label="", #real=0.00298881100025028, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.0, #total=0.0>
I hope it helps

getting the file in a sub-folder # Isolated Storage - WP7

I would like to get all the files that a sub-folder holds in a string array.
So, I have tried something like the following:
var IOstore = IsolatedStorageFile.GetUserStoreForApplication();
string searchpath = System.IO.Path.Combine("product", ProductName);
string filesInSubDirs[] = IOstore.GetFileNames(searchpath);
But I got all the files in the "product" folder. I have also tried with "productname" only as the parameter.
Thanks for your help.
The search pattern for a sub-folder needs to include "*.*" at the end to pattern match any file, which would make your code something like the following:
var IOstore = IsolatedStorageFile.GetUserStoreForApplication();
string searchpath = System.IO.Path.Combine("product", ProductName);
searchpath = string.Format("{0}\\*.*", searchpath);
string filesInSubDirs[] = IOstore.GetFileNames(searchpath);
Something you might want to try. (this is sort of a left field answer, sorry). In my dropbox client http://sharpdropbox.codeplex.com/) I have a set of facades for System.IO.File, System.IO.FileInfo, System.IO.Directory, and System.IO.DirectoryInfo. They work pretty good and I have tested them.
Basically, you add a Using or Import for System.IO.IsolatedStorage and then PSFile, PSDirectory, PSFileInfo, or PSDirectoryInfo. It's saved me from having to remember all the nuances... for instance if you are querying a directory, it knows to add a slash, etc. BTW, the "PS" prefix stands for "Persisted Storage" which is what IsolatedStorage is sometimes called (starting them with an "I" implies they are interfaces.. and having no prefix makes things even more confusing).
Anyway, you can grab the code from source or I believe the last release had the DLLs for them (it's called something like "IsolatedStorageFacade-WP7")

Resources