-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
466 additions
and
0 deletions.
There are no files selected for viewing
210 changes: 210 additions & 0 deletions
210
common/src/main/kotlin/tech/cuda/woden/common/service/VersionControlService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package tech.cuda.woden.common.service | ||
|
||
import me.liuwj.ktorm.database.Database | ||
import me.liuwj.ktorm.dsl.* | ||
import me.liuwj.ktorm.global.addEntity | ||
import me.liuwj.ktorm.global.global | ||
import me.liuwj.ktorm.global.select | ||
import me.liuwj.ktorm.global.update | ||
import tech.cuda.woden.common.service.dao.CommitmentDAO | ||
import tech.cuda.woden.common.service.dao.WorkingTreeDAO | ||
import tech.cuda.woden.common.service.dto.CommitmentDTO | ||
import tech.cuda.woden.common.service.dto.WorkingTreeDTO | ||
import tech.cuda.woden.common.service.dto.toCommitmentDTO | ||
import tech.cuda.woden.common.service.dto.toWorkingTreeDTO | ||
import tech.cuda.woden.common.service.exception.NotFoundException | ||
import tech.cuda.woden.common.service.po.CommitmentPO | ||
import tech.cuda.woden.common.service.po.WorkingTreePO | ||
import java.time.LocalDateTime | ||
|
||
/** | ||
* @author Jensen Qi <[email protected]> | ||
* @since 0.1.0 | ||
*/ | ||
object VersionControlService { | ||
|
||
private fun requireDirectory(node: WorkingTreePO) = require(node.name.split(".").size == 1) { | ||
"Tree Node ${node.name} must be a directory" | ||
} | ||
|
||
|
||
private fun requireNonDirectory(node: WorkingTreePO) = require(node.name.split(".").size > 1) { | ||
"Tree Node ${node.name} can not be a directory" | ||
} | ||
|
||
internal fun selectWorkingTreeById(nodeId: Int) = WorkingTreeDAO.select() | ||
.where { (WorkingTreeDAO.isRemove eq false) and (WorkingTreeDAO.id eq nodeId) } | ||
.map { WorkingTreeDAO.createEntity(it) } | ||
.firstOrNull() | ||
|
||
|
||
internal fun selectCommitmentById(commitId: Int) = CommitmentDAO.select() | ||
.where { (CommitmentDAO.isRemove eq false) and (CommitmentDAO.id eq commitId) } | ||
.map { CommitmentDAO.createEntity(it) } | ||
.firstOrNull() | ||
|
||
/** | ||
* 创建一个 workingTree 的根节点并返回 | ||
*/ | ||
fun createWorkingTree(): WorkingTreeDTO { | ||
Database.global.useTransaction { | ||
val now = LocalDateTime.now() | ||
val workingTree = WorkingTreePO { | ||
this.name = "root" | ||
this.parentId = null | ||
this.stage = null | ||
this.commitId = null | ||
this.isRemove = false | ||
this.createTime = now | ||
this.updateTime = now | ||
}.also { WorkingTreeDAO.addEntity(it) } | ||
return workingTree.toWorkingTreeDTO() | ||
} | ||
} | ||
|
||
/** | ||
* 创建节点名称为[name],父节点为[parentId]的 Working Tree 节点 | ||
* 如果[parentId]对应的节点不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[parentId]不为目录节点,则抛出[IllegalArgumentException] | ||
*/ | ||
fun createWorkingNode(name: String, parentId: Int): WorkingTreeDTO = Database.global.useTransaction { | ||
val parent = selectWorkingTreeById(parentId) ?: throw NotFoundException() | ||
requireDirectory(parent) | ||
val now = LocalDateTime.now() | ||
val workingTree = WorkingTreePO { | ||
this.name = name | ||
this.parentId = parent.id | ||
this.stage = null | ||
this.commitId = null | ||
this.isRemove = false | ||
this.createTime = now | ||
this.updateTime = now | ||
}.also { WorkingTreeDAO.addEntity(it) } | ||
return workingTree.toWorkingTreeDTO() | ||
} | ||
|
||
/** | ||
* 查找 working Tree 中节点 ID 为 [nodeId] 的发布历史 | ||
* 如果[nodeId]节点不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[nodeId]节点为目录节点,则抛出[IllegalArgumentException] | ||
*/ | ||
fun listingCommitHistory(nodeId: Int): List<CommitmentDTO> { | ||
val node = selectWorkingTreeById(nodeId) ?: throw NotFoundException() | ||
requireNonDirectory(node) | ||
return CommitmentDAO.select() | ||
.where { (CommitmentDAO.nodeId eq nodeId) and (CommitmentDAO.isRemove eq false) } | ||
.orderBy(CommitmentDAO.createTime.desc()) | ||
.map { CommitmentDAO.createEntity(it).toCommitmentDTO() } | ||
} | ||
|
||
/** | ||
* 列出 WorkingTree 中节点 ID 为 [nodeId] 的所有子节点 | ||
* 如果[nodeId]节点不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[nodeId]节点不为目录节点,则抛出[IllegalArgumentException] | ||
*/ | ||
fun listingChildren(nodeId: Int): List<WorkingTreeDTO> { | ||
val node = selectWorkingTreeById(nodeId) ?: throw NotFoundException() | ||
requireDirectory(node) | ||
return WorkingTreeDAO.select() | ||
.where { (WorkingTreeDAO.isRemove eq false) and (WorkingTreeDAO.parentId eq node.id) } | ||
.map { WorkingTreeDAO.createEntity(it).toWorkingTreeDTO() } | ||
} | ||
|
||
|
||
/** | ||
* 删除 workingTree 中的节点 ID 为 [nodeId] 的节点 | ||
* 如果[nodeId]节点不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[nodeId]节点为根节点,则抛出[IllegalArgumentException] | ||
*/ | ||
fun remove(nodeId: Int) = Database.global.useTransaction { | ||
val node = selectWorkingTreeById(nodeId) ?: throw NotFoundException() | ||
require(node.parentId != null) { "can not remove root dir /" } | ||
node.isRemove = true | ||
node.updateTime = LocalDateTime.now() | ||
node.flushChanges() | ||
} | ||
|
||
/** | ||
* 获取节点 ID 为 [nodeId] 的当前 commit | ||
* 如果[nodeId]节点不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[nodeId]节点为目录节点,则抛出[IllegalArgumentException] | ||
* 如果[nodeId]不存在已提交的 commit,则抛出[IllegalArgumentException] | ||
*/ | ||
fun getCurrentCommit(nodeId: Int): CommitmentDTO { | ||
val node = selectWorkingTreeById(nodeId) ?: throw NotFoundException() | ||
requireNonDirectory(node) | ||
require(node.commitId != null) { "current has no committed" } | ||
val commitment = selectCommitmentById(node.commitId!!) ?: throw NotFoundException() | ||
return commitment.toCommitmentDTO() | ||
} | ||
|
||
/** | ||
* 将 [content] 写入 ID 为 [nodeId] 的节点缓存区 | ||
* 如果[nodeId]节点不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[nodeId]节点为目录节点,则抛出[IllegalArgumentException] | ||
*/ | ||
fun writeStage(nodeId: Int, content: String) = Database.global.useTransaction { | ||
val node = selectWorkingTreeById(nodeId) ?: throw NotFoundException() | ||
requireNonDirectory(node) | ||
node.stage = content | ||
node.updateTime = LocalDateTime.now() | ||
node.flushChanges() | ||
} | ||
|
||
/** | ||
* 发布 ID 为 [nodeId] 的节点中的缓存区 | ||
* 如果[nodeId]节点不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[nodeId]为目录节点,则抛出[IllegalArgumentException] | ||
* 如果[nodeId]的缓存区为 null,则抛出[IllegalArgumentException] | ||
*/ | ||
fun commit(nodeId: Int, message: String): CommitmentDTO = Database.global.useTransaction { | ||
val node = selectWorkingTreeById(nodeId) ?: throw NotFoundException() | ||
requireNonDirectory(node) | ||
require(node.stage != null) { "Stage of tree node ${node.name} is null" } | ||
val now = LocalDateTime.now() | ||
val commitment = CommitmentPO { | ||
this.nodeId = node.id | ||
this.content = node.stage!! | ||
this.message = message | ||
this.isRemove = false | ||
this.createTime = now | ||
this.updateTime = now | ||
}.also { CommitmentDAO.addEntity(it) } | ||
WorkingTreeDAO.update { | ||
set(it.commitId, commitment.id) | ||
set(it.updateTime, now) | ||
where { it.id eq node.id } | ||
} | ||
return commitment.toCommitmentDTO() | ||
} | ||
|
||
/** | ||
* 将 ID 为 [nodeId] 的节点回滚为 ID 为 [commitID] 的 commitment | ||
* 如果[nodeId]节点或已被删除,则抛出[NotFoundException] | ||
* 如果[commitID]提交不存在或已被删除,则抛出[NotFoundException] | ||
* 如果[nodeId]为目录节点,则抛出[IllegalArgumentException] | ||
* 如果[commitID]不归属与 [nodeId],则抛出[IllegalStateException] | ||
*/ | ||
fun rollback(nodeId: Int, commitID: Int) = Database.global.useTransaction { | ||
val node = selectWorkingTreeById(nodeId) ?: throw NotFoundException() | ||
val commitment = selectCommitmentById(commitID) ?: throw NotFoundException() | ||
requireNonDirectory(node) | ||
check(commitment.nodeId == node.id) { "commitment ${commitment.id} do not belong to node ${node.id}" } | ||
node.stage = commitment.content | ||
node.commitId = commitment.id | ||
node.updateTime = LocalDateTime.now() | ||
node.flushChanges() | ||
} | ||
|
||
|
||
} |
59 changes: 59 additions & 0 deletions
59
common/src/main/kotlin/tech/cuda/woden/common/service/dao/CommitmentDAO.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package tech.cuda.woden.common.service.dao | ||
|
||
import me.liuwj.ktorm.schema.* | ||
import tech.cuda.woden.annotation.mysql.* | ||
import tech.cuda.woden.common.service.mysql.type.longtext | ||
import tech.cuda.woden.common.service.po.CommitmentPO | ||
|
||
/** | ||
* @author Jensen Qi <[email protected]> | ||
* @since 0.1.0 | ||
*/ | ||
@STORE_IN_MYSQL | ||
internal object CommitmentDAO : Table<CommitmentPO>("commitment") { | ||
@BIGINT | ||
@UNSIGNED | ||
@AUTO_INCREMENT | ||
@PRIMARY_KEY | ||
@COMMENT("commit ID") | ||
val id = int("id").primaryKey().bindTo { it.id } | ||
|
||
@BIGINT | ||
@UNSIGNED | ||
@COMMENT("归属的 Working Tree 节点 ID") | ||
val nodeId = int("node_id").bindTo { it.nodeId } | ||
|
||
@LONGTEXT | ||
@COMMENT("commit 内容") | ||
val content = longtext("content").bindTo { it.content } | ||
|
||
@VARCHAR(256) | ||
@COMMENT("commit 注释") | ||
val message = varchar("message").bindTo { it.message } | ||
|
||
@BOOL | ||
@COMMENT("逻辑删除") | ||
val isRemove = boolean("is_remove").bindTo { it.isRemove } | ||
|
||
@DATETIME | ||
@COMMENT("创建时间") | ||
val createTime = datetime("create_time").bindTo { it.createTime } | ||
|
||
@DATETIME | ||
@COMMENT("更新时间") | ||
val updateTime = datetime("update_time").bindTo { it.updateTime } | ||
|
||
} |
64 changes: 64 additions & 0 deletions
64
common/src/main/kotlin/tech/cuda/woden/common/service/dao/WorkingTreeDAO.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package tech.cuda.woden.common.service.dao | ||
|
||
import me.liuwj.ktorm.schema.* | ||
import tech.cuda.woden.annotation.mysql.* | ||
import tech.cuda.woden.common.service.mysql.type.longtext | ||
import tech.cuda.woden.common.service.po.WorkingTreePO | ||
|
||
/** | ||
* @author Jensen Qi <[email protected]> | ||
* @since 0.1.0 | ||
*/ | ||
@STORE_IN_MYSQL | ||
internal object WorkingTreeDAO : Table<WorkingTreePO>("working_tree") { | ||
@BIGINT | ||
@UNSIGNED | ||
@AUTO_INCREMENT | ||
@PRIMARY_KEY | ||
@COMMENT("Working Tree 节点 ID") | ||
val id = int("id").primaryKey().bindTo { it.id } | ||
|
||
|
||
@VARCHAR(256) | ||
@COMMENT("节点名,有后缀的为叶子节点,无后缀的为非叶子节点(即目录节点)") | ||
val name = varchar("name").bindTo { it.name } | ||
|
||
@BIGINT | ||
@UNSIGNED | ||
@COMMENT("父节点ID") | ||
val parentId = int("parent_id").bindTo { it.parentId } | ||
|
||
@LONGTEXT | ||
@COMMENT("当前 stage 区内容") | ||
val stage = longtext("stage").bindTo { it.stage } | ||
|
||
@BIGINT | ||
@UNSIGNED | ||
@COMMENT("当天已发布的 commit ID") | ||
val commitId = int("commit_id").bindTo { it.commitId } | ||
|
||
@BOOL | ||
@COMMENT("逻辑删除") | ||
val isRemove = boolean("is_remove").bindTo { it.isRemove } | ||
|
||
@DATETIME | ||
@COMMENT("创建时间") | ||
val createTime = datetime("create_time").bindTo { it.createTime } | ||
|
||
@DATETIME | ||
@COMMENT("更新时间") | ||
val updateTime = datetime("update_time").bindTo { it.updateTime } | ||
} |
33 changes: 33 additions & 0 deletions
33
common/src/main/kotlin/tech/cuda/woden/common/service/dto/CommitmentDTO.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package tech.cuda.woden.common.service.dto | ||
|
||
import tech.cuda.woden.annotation.pojo.DTO | ||
import tech.cuda.woden.common.service.po.CommitmentPO | ||
import tech.cuda.woden.common.service.po.ContainerPO | ||
import java.time.LocalDateTime | ||
|
||
/** | ||
* @author Jensen Qi <[email protected]> | ||
* @since 0.1.0 | ||
*/ | ||
@DTO(CommitmentPO::class) | ||
data class CommitmentDTO( | ||
val id: Int, | ||
val nodeId: Int, | ||
val content: String, | ||
val message: String, | ||
val createTime: LocalDateTime, | ||
val updateTime: LocalDateTime | ||
) |
Oops, something went wrong.