From 9778ad6647265d3d305c8985f3630ac0636326d9 Mon Sep 17 00:00:00 2001 From: darwincereska Date: Thu, 6 Nov 2025 11:23:40 -0500 Subject: [PATCH] feat(repo): added minimal repo class --- CHECKLIST.md | 6 +- build.gradle.kts | 31 +++++- src/main/kotlin/io/notevc/NoteVC.kt | 30 +++++- .../kotlin/io/notevc/commands/InitCommand.kt | 25 +++++ src/main/kotlin/io/notevc/core/Repository.kt | 102 ++++++++++++++++++ src/main/kotlin/io/notevc/utils/FileUtils.kt | 2 + 6 files changed, 187 insertions(+), 9 deletions(-) diff --git a/CHECKLIST.md b/CHECKLIST.md index b7bfca8..c11a53a 100644 --- a/CHECKLIST.md +++ b/CHECKLIST.md @@ -2,12 +2,12 @@ - [x] Initialize Project - [x] Configure `build.gradle.kts` with dependencies -- [ ] Set up testing framework +- [x] Set up testing framework # Core -- [ ] Create `Repository.kt` class -- [ ] Implement `.notevc` directory initialization +- [x] Create `Repository.kt` class +- [x] Implement `.notevc` directory initialization - [ ] Create `ObjectStore.kt` for content storage - [ ] Implement content hashing `HashUtils.kt` - [ ] Create `NoteSnapshot` data class diff --git a/build.gradle.kts b/build.gradle.kts index 27859e7..e82b497 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,25 +1,48 @@ +import java.time.Instant + plugins { kotlin("jvm") version "2.2.21" + kotlin("plugin.serialization") version "2.2.21" application + id("com.github.gmazzo.buildconfig") version "4.1.2" + id("com.gradleup.shadow") version "9.2.2" } group = "io.notevc" version = "1.0.0" +buildConfig { + buildConfigField("String", "VERSION", "\"${project.version}\"") + buildConfigField("String", "BUILD_TIME", "\"${Instant.now()}\"") + packageName("io.notevc") +} + repositories { mavenCentral() } dependencies { + val junitVersion = "5.10.0" implementation(kotlin("stdlib")) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") + + testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion") } application { mainClass.set("io.notevc.NoteVCKt") } -tasks.jar { - manifest { - attributes["Main-Class"] = "io.notevc.NoteVCKt" - } +tasks.withType { + useJUnitPlatform() } + +tasks.build { + dependsOn(tasks.shadowJar) +} + +tasks.jar { + enabled = false +} + diff --git a/src/main/kotlin/io/notevc/NoteVC.kt b/src/main/kotlin/io/notevc/NoteVC.kt index c5498f5..e07fd15 100644 --- a/src/main/kotlin/io/notevc/NoteVC.kt +++ b/src/main/kotlin/io/notevc/NoteVC.kt @@ -1,5 +1,31 @@ package io.notevc -fun main() { - println("hello world") +import io.notevc.core.Repository +import io.notevc.commands.* + +fun main(args: Array) { + // Args logic + when (args.firstOrNull()) { + "init" -> { + val initCommand = InitCommand() + val result = initCommand.execute(args.getOrNull(1)) + + result.fold( + onSuccess = { message -> println(message) }, + onFailure = { error -> println("Error: ${error.message}") } + ) + } + + "commit" -> { + println("Not implemented yet") + } + + "status" -> { + println("Not implemented yet") + } + + "version", "--version", "-v" -> { + println("notevc version ${Repository.VERSION}") + } + } } diff --git a/src/main/kotlin/io/notevc/commands/InitCommand.kt b/src/main/kotlin/io/notevc/commands/InitCommand.kt index a1f7d85..3ef238a 100644 --- a/src/main/kotlin/io/notevc/commands/InitCommand.kt +++ b/src/main/kotlin/io/notevc/commands/InitCommand.kt @@ -1 +1,26 @@ package io.notevc.commands + +import io.notevc.core.Repository +import java.nio.file.Path + +class InitCommand { + fun execute(path: String?): Result { + return try { + val repo = if (path != null) { + Repository.at(path).getOrElse { return Result.failure(it) } + } else Repository.current() + + repo.init().fold( + onSuccess = { + Result.success("Initialized notevc repository in ${repo.path.toAbsolutePath()}") + }, + onFailure = { + error -> Result.failure(error) + } + ) + } + catch (e: Exception) { + Result.failure(e) + } + } +} diff --git a/src/main/kotlin/io/notevc/core/Repository.kt b/src/main/kotlin/io/notevc/core/Repository.kt index 06fd659..aec69a4 100644 --- a/src/main/kotlin/io/notevc/core/Repository.kt +++ b/src/main/kotlin/io/notevc/core/Repository.kt @@ -1 +1,103 @@ package io.notevc.core + +import java.nio.file.Path +import java.nio.file.Paths +import kotlin.io.path.* +import io.notevc.BuildConfig +import kotlinx.serialization.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.encodeToString +import java.nio.file.Files +import java.time.Instant + +class Repository private constructor(private val rootPath: Path) { + private val notevcDir = rootPath.resolve(NOTEVC_DIR) + val path: Path get() = rootPath + val isInitialized: Boolean get() = notevcDir.exists() + + companion object { + // Factory methods - these create Repository instances + + // Create repository at a specified path + fun at(path: String): Result { + return try { + val absolutePath = Path.of(path).toAbsolutePath() + when { + !absolutePath.exists() -> Result.failure(Exception("Directory does not exist: $path")) + !absolutePath.isDirectory() -> Result.failure(Exception("Path is not directory: $path")) + !absolutePath.isWritable() -> Result.failure(Exception("Directory is not writable: $path")) + else -> Result.success(Repository(absolutePath)) + } + } + catch (e: Exception) { + Result.failure(e) + } + } + + // Create repository at current directory + fun current(): Repository = Repository(Path.of(System.getProperty("user.dir")).toAbsolutePath()) + + // Find existing repository by walking up + fun find(): Repository? { + var current = Path.of(System.getProperty("user.dir")).toAbsolutePath() + while (current != null) { + if (current.resolve(NOTEVC_DIR).exists()) return Repository(current) + current = current.parent // Go up one level + } + return null // No repository found + } + + // Constants + const val NOTEVC_DIR = ".notevc" + val VERSION = BuildConfig.VERSION + val BUILD_TIME = BuildConfig.BUILD_TIME + + } + + override fun toString(): String = "Repository(path=${rootPath.toAbsolutePath()}, initialized=$isInitialized)" + + fun init(): Result { + return try { + // Check if already initialized + if (isInitialized) return Result.failure(Exception("Repository already initialized at ${rootPath.toAbsolutePath()}")) + + // Create .notevc directory structure + Files.createDirectories(notevcDir) + Files.createDirectories(notevcDir.resolve("objects")) + + // Create initial metadata + val metadata = RepoMetadata( + version = VERSION, + created = Instant.now().toString(), + head = null + ) + + // Save metadata to .notevc/metadata.json + val metadataFile = notevcDir.resolve("metadata.json") + Files.writeString(metadataFile, Json.encodeToString(metadata)) + + // Create empty timeline + val timelineFile = notevcDir.resolve("timeline.json") + Files.writeString(timelineFile, "[]") + + Result.success(Unit) + } + catch (e: Exception) { + Result.failure(e) + } + } +} + +@Serializable +data class RepoMetadata( + val version: String, + val created: String, + var head: String? +) + +@Serializable +data class RepoConfig( + val autoCommit: Boolean = false, + val compressionEnabled: Boolean = false, + val maxSnapshots: Int = 100 +) diff --git a/src/main/kotlin/io/notevc/utils/FileUtils.kt b/src/main/kotlin/io/notevc/utils/FileUtils.kt index 5675552..3f954f8 100644 --- a/src/main/kotlin/io/notevc/utils/FileUtils.kt +++ b/src/main/kotlin/io/notevc/utils/FileUtils.kt @@ -1 +1,3 @@ package io.notevc.utils + +