Improve samples (#396)
This commit is contained in:
+1
-1
@@ -95,7 +95,7 @@ private fun ProcessBuilder.runExpectingSuccess() {
|
||||
}
|
||||
|
||||
private fun Properties.getSpaceSeparated(name: String): List<String> {
|
||||
return this.getProperty(name)?.split(' ') ?: emptyList()
|
||||
return this.getProperty(name)?.split(' ')?.filter { it.isNotEmpty() } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun Properties.getOsSpecific(name: String,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CVS parser
|
||||
# CSV parser
|
||||
|
||||
This example shows how one could implement simple CSV reader and parser in Kotlin.
|
||||
This example shows how one could implement simple comma separated values reader and parser in Kotlin.
|
||||
A sample data [European Mammals Red List for 2009] (https://data.europa.eu/euodp/en/data/dataset?res_format=CSV)
|
||||
from EU is being used.
|
||||
|
||||
@@ -10,5 +10,4 @@ To run use
|
||||
|
||||
./CsvParser.kexe ./European_Mammals_Red_List_Nov_2009.csv 4 100
|
||||
|
||||
Which will print fifth column (Family, zero-based index) in first 100 rows of the
|
||||
CSV file.
|
||||
It will print fifth column (Family, zero-based index) in first 100 rows of the CSV file.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# GIT frequency analyzer
|
||||
|
||||
This example shows how one could perform statistics on Git repository.
|
||||
|
||||
To build use `./build.sh` script without arguments (or specify `TARGET` variable if cross-compiling).
|
||||
|
||||
To run use
|
||||
|
||||
./GitChurn.kexe <path-to-some-git-repo>
|
||||
|
||||
It will print most frequently modified (by number of commits) files in repository.
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PATH=../../dist/bin:../../bin:$PATH
|
||||
DIR=.
|
||||
|
||||
CFLAGS_macbook=-I/opt/local/include
|
||||
CFLAGS_linux=-I/usr/include
|
||||
LINKER_ARGS_macbook="-L/opt/local/lib -lgit2"
|
||||
LINKER_ARGS_linux="-L/usr/lib/x86_64-linux-gnu -lgit2"
|
||||
|
||||
if [ x$TARGET == x ]; then
|
||||
case "$OSTYPE" in
|
||||
darwin*) TARGET=macbook ;;
|
||||
linux*) TARGET=linux ;;
|
||||
*) echo "unknown: $OSTYPE" && exit 1;;
|
||||
esac
|
||||
fi
|
||||
|
||||
var=CFLAGS_${TARGET}
|
||||
CFLAGS=${!var}
|
||||
var=LINKER_ARGS_${TARGET}
|
||||
LINKER_ARGS=${!var}
|
||||
var=COMPILER_ARGS_${TARGET}
|
||||
COMPILER_ARGS=${!var} # add -opt for an optimized build.
|
||||
|
||||
interop -copt:$CFLAGS -def:$DIR/libgit2.def -target:$TARGET || exit 1
|
||||
konanc -target $TARGET src libgit2 -nativelibrary libgit2stubs.bc -linkerArgs "$LINKER_ARGS" -o GitChurn.kexe || exit 1
|
||||
@@ -0,0 +1,3 @@
|
||||
headers = git2.h
|
||||
linkerOpts = -lgit2
|
||||
excludedFunctions =
|
||||
@@ -0,0 +1,3 @@
|
||||
fun main(args: Array<String>) {
|
||||
org.konan.libgit.main(args)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.konan.libgit
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import libgit2.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
if (args.size == 0)
|
||||
return help()
|
||||
|
||||
val workDir = args[0]
|
||||
val limit = if (args.size > 1) {
|
||||
args[1].toInt()
|
||||
} else
|
||||
null
|
||||
|
||||
println("Opening…")
|
||||
val repository = git.repository(workDir)
|
||||
val map = mutableMapOf<String, Int>()
|
||||
var count = 0
|
||||
val commits = repository.commits()
|
||||
val limited = limit?.let { commits.take(it) } ?: commits
|
||||
println("Calculating…")
|
||||
limited.forEach { commit ->
|
||||
if (count % 100 == 0)
|
||||
println("Commit #$count [${commit.time.format()}]: ${commit.summary}")
|
||||
|
||||
commit.parents.forEach { parent ->
|
||||
val diff = commit.tree.diff(parent.tree)
|
||||
diff.deltas().forEach { delta ->
|
||||
val path = delta.newPath
|
||||
val n = map[path] ?: 0
|
||||
map.put(path, n + 1)
|
||||
}
|
||||
diff.close()
|
||||
parent.close()
|
||||
}
|
||||
commit.close()
|
||||
count++
|
||||
}
|
||||
println("Report:")
|
||||
map.toList().sortedByDescending { it.second }.take(10).forEach {
|
||||
println("File: ${it.first}")
|
||||
println(" ${it.second}")
|
||||
println()
|
||||
}
|
||||
|
||||
repository.close()
|
||||
git.close()
|
||||
}
|
||||
|
||||
fun git_time_t.format() = memScoped {
|
||||
val commitTime = alloc<time_tVar>()
|
||||
commitTime.value = this@format
|
||||
ctime(commitTime.ptr)!!.toKString().trim()
|
||||
}
|
||||
|
||||
|
||||
private fun printTree(commit: GitCommit) {
|
||||
commit.tree.entries().forEach { entry ->
|
||||
when (entry) {
|
||||
is GitTreeEntry.File -> println(" ${entry.name}")
|
||||
is GitTreeEntry.Folder -> println(" /${entry.name} (${entry.subtree.entries().size})")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun help() {
|
||||
println("Working directory should be provided")
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.konan.libgit
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import libgit2.*
|
||||
|
||||
class GitCommit(val repository: GitRepository, val commit: CPointer<git_commit>) {
|
||||
fun close() = git_commit_free(commit)
|
||||
|
||||
val summary: String get() = git_commit_summary(commit)!!.toKString()
|
||||
val time: git_time_t get() = git_commit_time(commit)
|
||||
|
||||
val tree: GitTree get() = memScoped {
|
||||
val treePtr = allocPointerTo<git_tree>()
|
||||
git_commit_tree(treePtr.ptr, commit).errorCheck()
|
||||
GitTree(repository, treePtr.value!!)
|
||||
}
|
||||
|
||||
val parents: List<GitCommit> get() = memScoped {
|
||||
val count = git_commit_parentcount(commit)
|
||||
val result = ArrayList<GitCommit>(count)
|
||||
for (index in 0..count - 1) {
|
||||
val commitPtr = allocPointerTo<git_commit>()
|
||||
git_commit_parent(commitPtr.ptr, commit, index).errorCheck()
|
||||
result.add(GitCommit(repository, commitPtr.value!!))
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.konan.libgit
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import libgit2.*
|
||||
|
||||
class GitDiff(val repository: GitRepository, val handle: CPointer<git_diff>) {
|
||||
fun deltas(): List<GifDiffDelta> {
|
||||
val size = git_diff_num_deltas(handle)
|
||||
val results = ArrayList<GifDiffDelta>(size.toInt())
|
||||
for (index in 0..size - 1) {
|
||||
val delta = git_diff_get_delta(handle, index)
|
||||
results.add(GifDiffDelta(this, delta!!))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
fun close() {
|
||||
git_diff_free(handle)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GifDiffDelta(val diff: GitDiff, val handle: CPointer<git_diff_delta>) {
|
||||
|
||||
val status get() = handle.pointed.status.value
|
||||
val newPath get() = handle.pointed.new_file.path.value!!.toKString()
|
||||
val oldPath get() = handle.pointed.old_file.path.value!!.toKString()
|
||||
|
||||
fun status(): String {
|
||||
return when (status) {
|
||||
GIT_DELTA_ADDED -> "A"
|
||||
GIT_DELTA_DELETED -> "D"
|
||||
GIT_DELTA_MODIFIED -> "M"
|
||||
GIT_DELTA_RENAMED -> "R"
|
||||
GIT_DELTA_COPIED -> "C"
|
||||
else -> throw Exception("Unsupported delta status $status")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.konan.libgit
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import libgit2.*
|
||||
|
||||
class GitRemote(val repository: GitRepository, val handle: CPointer<git_remote>) {
|
||||
fun close() = git_remote_free(handle)
|
||||
|
||||
val url: String get() = git_remote_url(handle)!!.toKString()
|
||||
val name: String = git_remote_name(handle)!!.toKString()
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.konan.libgit
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import libgit2.*
|
||||
|
||||
class GitRepository(val location: String) {
|
||||
val arena = Arena()
|
||||
val handle: CPointer<git_repository> = memScoped {
|
||||
val loc = allocPointerTo<git_repository>()
|
||||
git_repository_open(loc.ptr, location).errorCheck()
|
||||
loc.value!!
|
||||
}
|
||||
|
||||
fun close() {
|
||||
git_repository_free(handle)
|
||||
arena.clear()
|
||||
}
|
||||
|
||||
fun remotes(): List<GitRemote> = memScoped {
|
||||
val remoteList = alloc<git_strarray>()
|
||||
git_remote_list(remoteList.ptr, handle).errorCheck()
|
||||
val size = remoteList.count.value.toInt()
|
||||
val list = ArrayList<GitRemote>(size)
|
||||
for (index in 0..size - 1) {
|
||||
val array = remoteList.strings.value!!.reinterpret<CArray<CPointerVar<CInt8Var>>>().pointed
|
||||
val name = array[index].value!!.toKString()
|
||||
val remotePtr = allocPointerTo<git_remote>()
|
||||
git_remote_lookup(remotePtr.ptr, handle, name).errorCheck()
|
||||
list.add(GitRemote(this@GitRepository, remotePtr.value!!))
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
fun commits(): Sequence<GitCommit> = memScoped {
|
||||
val walkPtr = allocPointerTo<git_revwalk>()
|
||||
git_revwalk_new(walkPtr.ptr, handle).errorCheck()
|
||||
val walk = walkPtr.value
|
||||
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL or GIT_SORT_TIME)
|
||||
git_revwalk_push_head(walk).errorCheck()
|
||||
generateSequence<GitCommit> {
|
||||
memScoped {
|
||||
val oid = alloc<git_oid>()
|
||||
val result = git_revwalk_next(oid.ptr, walk)
|
||||
|
||||
when (result) {
|
||||
0 -> {
|
||||
val commitPtr = allocPointerTo<git_commit>()
|
||||
git_commit_lookup(commitPtr.ptr, handle, oid.ptr).errorCheck()
|
||||
val commit = commitPtr.value!!
|
||||
GitCommit(this@GitRepository, commit)
|
||||
}
|
||||
GIT_ITEROVER -> null
|
||||
else -> throw Exception("Unexpected result code $result")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.konan.libgit
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import libgit2.*
|
||||
|
||||
class GitTree(val repository: GitRepository, val handle: CPointer<git_tree>) {
|
||||
fun close() = git_tree_free(handle)
|
||||
|
||||
fun entries(): List<GitTreeEntry> = memScoped {
|
||||
val size = git_tree_entrycount(handle)
|
||||
val entries = ArrayList<GitTreeEntry>(size.toInt())
|
||||
for (index in 0..size - 1) {
|
||||
val treeEntry = git_tree_entry_byindex(handle, index)!!
|
||||
val entryType = git_tree_entry_type(treeEntry)
|
||||
val entry = when (entryType) {
|
||||
GIT_OBJ_TREE -> memScoped {
|
||||
val id = git_tree_entry_id(treeEntry)
|
||||
val treePtr = allocPointerTo<git_tree>()
|
||||
git_tree_lookup(treePtr.ptr, repository.handle, id)
|
||||
GitTreeEntry.Folder(this@GitTree, treeEntry, treePtr.value!!)
|
||||
}
|
||||
GIT_OBJ_BLOB -> GitTreeEntry.File(this@GitTree, treeEntry)
|
||||
else -> throw Exception("Unsupported entry type $entryType")
|
||||
}
|
||||
entries.add(entry)
|
||||
}
|
||||
entries
|
||||
}
|
||||
|
||||
fun diff(other: GitTree): GitDiff = memScoped {
|
||||
val diffPtr = allocPointerTo<git_diff>()
|
||||
git_diff_tree_to_tree(diffPtr.ptr, repository.handle, handle, other.handle, null).errorCheck()
|
||||
GitDiff(repository, diffPtr.value!!)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class GitTreeEntry(val tree: GitTree, val handle: CPointer<git_tree_entry>) {
|
||||
val name: String get() = git_tree_entry_name(handle)!!.toKString()
|
||||
|
||||
class Folder(tree: GitTree, handle: CPointer<git_tree_entry>, val subtreeHandle: CPointer<git_tree>) : GitTreeEntry(tree, handle) {
|
||||
val subtree = GitTree(tree.repository, subtreeHandle)
|
||||
}
|
||||
|
||||
class File(tree: GitTree, handle: CPointer<git_tree_entry>) : GitTreeEntry(tree, handle)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.konan.libgit
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import libgit2.*
|
||||
|
||||
object git {
|
||||
init {
|
||||
git_libgit2_init()
|
||||
}
|
||||
|
||||
fun close() {
|
||||
git_libgit2_shutdown()
|
||||
}
|
||||
|
||||
fun repository(location: String): GitRepository {
|
||||
return GitRepository(location)
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.errorCheck() {
|
||||
if (this == 0) return
|
||||
throw GitException()
|
||||
}
|
||||
|
||||
class GitException : Exception(run {
|
||||
val err = giterr_last()
|
||||
err!!.pointed.message.value!!.toKString()
|
||||
})
|
||||
@@ -4,7 +4,7 @@ PATH=../../dist/bin:../../bin:$PATH
|
||||
DIR=.
|
||||
|
||||
LINKER_ARGS_macbook="-framework OpenGL -framework GLUT"
|
||||
LINKER_ARGS_linux="-L/usr/lib/x86_64-linux-gnu -lSDL2"
|
||||
LINKER_ARGS_linux="-L/usr/lib/x86_64-linux-gnu -lglut -lGL -lGLU"
|
||||
|
||||
if [ x$TARGET == x ]; then
|
||||
case "$OSTYPE" in
|
||||
@@ -22,4 +22,5 @@ var=COMPILER_ARGS_${TARGET}
|
||||
COMPILER_ARGS=${!var} # add -opt for an optimized build.
|
||||
|
||||
interop -def:$DIR/opengl.def -target:$TARGET || exit 1
|
||||
konanc -target $TARGET opengl $DIR/OpenGlTeapot.kt -nativelibrary openglstubs.bc -linkerArgs "$LINKER_ARGS" -o OpenGlTeapot.kexe || exit 1
|
||||
# OpenGL stubs are rather big, so we need more heap space.
|
||||
konanc -J-Xmx2G -target $TARGET opengl $DIR/OpenGlTeapot.kt -nativelibrary openglstubs.bc -linkerArgs "$LINKER_ARGS" -o OpenGlTeapot.kexe || exit 1
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
headers = GLUT/glut.h
|
||||
compilerOpts = -framework OpenGL -framework GLUT
|
||||
headers =
|
||||
headers.osx = GLUT/glut.h
|
||||
headers.linux = GL/glut.h
|
||||
compilerOpts =
|
||||
compilerOpts.osx = -framework OpenGL -framework GLUT
|
||||
compilerOpts.linux = -I/usr/include
|
||||
|
||||
Reference in New Issue
Block a user