OMZXJL6QA6INENIEAARSWYFHOPMLTP4WRCVI646GQVJVWCH3LENQC A7IL6I3VCB3F3QMYQFPXBL33DN5XDGGQPZIBZRHYSQBSIUBBFQJQC 7L5LODGZ7AN4ZULDJZMLALD7PL6E57VZSNNSG67SFJARUJGCT47QC ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQC 2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWAC GGYFPXND4VBCROZZXTKAP7Y4JOP2OOYQAFVLMUE7SLFM225EUSIAC MTPTFTHGAOKQGRUDXC55AM6XJHZZZ5EF6FPVXKFVCUYVXJNEANYQC 37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6AC FNNW5IEAXQ43WKB6QSQB7DFLG3Y3T5FYPXIUX7KQ2URR2GU3QLTAC FRFFQV7VNYKGCA7ZAOSRPC2HHYTAIZ6AGGR7A5QEV6QPAQGFDYGAC B43WNBLFFR2UQIH3C6KIZAQTAEQOQM3J3IYLGQMVGJHYOME73OKQC Q7FXTHVUPVAFMNY277C3NFJO3VXLZU5G6C6UYSD5QPURHSG3A7OQC 6CR2EFUN7JXFHCBTNX3WWOOP4WFOCFO6KSPEBN6V6J5HFZO2LHNQC 5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQAC Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJAC OPFG6CZ26PPTGTH7ULLRQGZGR3YEIEJOV5W2E3WN7PFRZS62CVLQC QXUEMZ3B2FUHFUC7ZZHJMH5FVWLEMEYXUMFA6JNXTJKIVZNMRIOAC ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QC package com.github.jonathanxd.dracon.testimport com.github.jonathanxd.dracon.push.parsePijulPushChangesimport io.kotest.core.spec.style.ShouldSpecimport io.kotest.matchers.shouldBeclass DraconPushChangesTest : ShouldSpec({should("correctly parse a 'pijul push' text with example credit") {val text = """# Please select the changes to push. The lines that contain just a# valid hash, and no other character (except possibly a newline), will# be pushed.ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQCDependencies: Q7FXTHVUPVAFMNY277C3NFJO3VXLZU5G6C6UYSD5QPURHSG3A7OQC EAGIDXOLFTHZMZ77ZWAM7MVVUBBXJMZD7RZUNBHJPYRFGGKILGVACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-03-31 22:43:40.062881279 UTCImproved support for revisions5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQACDependencies: ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQCAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-01 00:07:39.373781350 UTCAdd support to view files affected by a revisionB43WNBLFFR2UQIH3C6KIZAQTAEQOQM3J3IYLGQMVGJHYOME73OKQCDependencies: 5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-01 17:04:54.758320581 UTC- Add Show History to Pijul menu- Always ignore .idea and .pijul in tracking.- Make findPijul a generic function to allow to find editor-server.- Only show one revision for directories.- Add `Hunk::resolvePath(Path)` to resolve the affected file to a Java NIO Path.- Fix StringOutOfBounds in Change Parsering Algorithm- Use editor-server instead of copie for interfacing with `pijul record` file.- Fix FileStatus provider not returning correctly for untracked files.- Add CommittedChangesProvider for Pijul.Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJACDependencies: B43WNBLFFR2UQIH3C6KIZAQTAEQOQM3J3IYLGQMVGJHYOME73OKQCAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-02 21:31:47.581509792 UTCRemove use of coroutines, which was blocking IntelliJ UI in larger repositoriesImprovements for bigger repositories, now Dracon caches the changes that happened in a revision in a file, so everytime Dracon needs to query the changes of a revision, it loads directly from memory instead of doing a full-scan in Pijul repository. For tiny projects it is not a problem, but for medium ones it takes more than five minutes to scan the entire repository (and it was tested with a repo of only 700 records, however there was changes that had more than 60.000 lines).The cache file is saved in IntelliJ Data Path (project specific) and is compressed with gzip, so it will not use so much disk space (the cost worths the gains).ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QCDependencies: Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-03 03:18:36.900275901 UTCMore caches, better and generic cache code.Now Dracon listen to file changes to drop cached data.Implemented caches:- File contents in specific revision (never dropped)- Pijul ls and Pijul diff results- File Revision and File changes by patch- some others..Dracon is incredible fast now, but still will take some time for bigger repos.2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWACDependencies: ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QCAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-04 03:15:58.713132084 UTCAdd auto installation support and cache content of ContentRevision37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6ACDependencies: A7JOR7M3BUKXYMMAR43IK4GXFXGI33HM6H6LZHDES3HWW6GYFAYAC G54TB4QZZ6OYC2KZTB7KUVW3NJ6VASH7WPNFU2IATPZWM3POIRNQC 2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-04 12:07:50.967878750 UTCImproved caching code a lotA7IL6I3VCB3F3QMYQFPXBL33DN5XDGGQPZIBZRHYSQBSIUBBFQJQCDependencies: 37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6ACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-04 18:38:01.065118605 UTCMore files to support .ignore""".trimIndent()val push = text.parsePijulPushChanges()push.toString() shouldBe "PijulPushChanges(entries=[PijulPushEntry(hash=ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQC, dependencies=[Q7FXTHVUPVAFMNY277C3NFJO3VXLZU5G6C6UYSD5QPURHSG3A7OQC, EAGIDXOLFTHZMZ77ZWAM7MVVUBBXJMZD7RZUNBHJPYRFGGKILGVAC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-03-31T22:43:40.062881279Z[Etc/UTC], message= Improved support for revisions\n" +"), PijulPushEntry(hash=5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQAC, dependencies=[ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-04-01T00:07:39.373781350Z[Etc/UTC], message= Add support to view files affected by a revision\n" +"), PijulPushEntry(hash=B43WNBLFFR2UQIH3C6KIZAQTAEQOQM3J3IYLGQMVGJHYOME73OKQC, dependencies=[5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQAC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-04-01T17:04:54.758320581Z[Etc/UTC], message= - Add Show History to Pijul menu\n" +" - Always ignore .idea and .pijul in tracking.\n" +" - Make findPijul a generic function to allow to find editor-server.\n" +" - Only show one revision for directories.\n" +" - Add `Hunk::resolvePath(Path)` to resolve the affected file to a Java NIO Path.\n" +" - Fix StringOutOfBounds in Change Parsering Algorithm\n" +" - Use editor-server instead of copie for interfacing with `pijul record` file.\n" +" - Fix FileStatus provider not returning correctly for untracked files.\n" +" - Add CommittedChangesProvider for Pijul.\n" +"), PijulPushEntry(hash=Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJAC, dependencies=[B43WNBLFFR2UQIH3C6KIZAQTAEQOQM3J3IYLGQMVGJHYOME73OKQC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-04-02T21:31:47.581509792Z[Etc/UTC], message= Remove use of coroutines, which was blocking IntelliJ UI in larger repositories\n" +"\n" +" Improvements for bigger repositories, now Dracon caches the changes that happened in a revision in a file, so everytime Dracon needs to query the changes of a revision, it loads directly from memory instead of doing a full-scan in Pijul repository. For tiny projects it is not a problem, but for medium ones it takes more than five minutes to scan the entire repository (and it was tested with a repo of only 700 records, however there was changes that had more than 60.000 lines).\n" +"\n" +" The cache file is saved in IntelliJ Data Path (project specific) and is compressed with gzip, so it will not use so much disk space (the cost worths the gains).\n" +"\n" +"), PijulPushEntry(hash=ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QC, dependencies=[Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJAC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-04-03T03:18:36.900275901Z[Etc/UTC], message= More caches, better and generic cache code.\n" +"\n" +"\n" +" Now Dracon listen to file changes to drop cached data.\n" +"\n" +" Implemented caches:\n" +"\n" +" - File contents in specific revision (never dropped)\n" +" - Pijul ls and Pijul diff results\n" +" - File Revision and File changes by patch\n" +" - some others..\n" +"\n" +"\n" +" Dracon is incredible fast now, but still will take some time for bigger repos.\n" +"), PijulPushEntry(hash=2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWAC, dependencies=[ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-04-04T03:15:58.713132084Z[Etc/UTC], message= Add auto installation support and cache content of ContentRevision\n" +"), PijulPushEntry(hash=37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6AC, dependencies=[A7JOR7M3BUKXYMMAR43IK4GXFXGI33HM6H6LZHDES3HWW6GYFAYAC, G54TB4QZZ6OYC2KZTB7KUVW3NJ6VASH7WPNFU2IATPZWM3POIRNQC, 2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWAC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-04-04T12:07:50.967878750Z[Etc/UTC], message= Improved caching code a lot\n" +"), PijulPushEntry(hash=A7IL6I3VCB3F3QMYQFPXBL33DN5XDGGQPZIBZRHYSQBSIUBBFQJQC, dependencies=[37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6AC], authors=[Author(name=Jonathan, fullName=Jonathan H. R. Lopes, email=jhrldev@gmail.com)], date=2021-04-04T18:38:01.065118605Z[Etc/UTC], message= More files to support .ignore\n" +"\n" +")])"}})
remote.invalid.remote.text=Invalid remote server {0}...
package com.github.jonathanxd.dracon.pushimport com.github.jonathanxd.dracon.log.PijulHashimport com.intellij.openapi.project.Projectimport com.intellij.openapi.vcs.changes.Changeimport com.intellij.openapi.vfs.VfsUtilimport com.intellij.openapi.vfs.VirtualFileimport com.intellij.openapi.vfs.VirtualFileManagerimport com.intellij.vcs.log.Hashimport com.intellij.vcs.log.VcsFullCommitDetailsimport com.intellij.vcs.log.VcsUserimport com.intellij.vcs.log.impl.VcsUserImplimport java.nio.file.Pathclass PijulVcsFullCommitDetails(val root: Path,val project: Project,val entry: PijulPushEntry,val changeRetriever: (String) -> List<Change>) : VcsFullCommitDetails {override fun getId(): Hash =PijulHash(this.entry.hash)override fun getParents(): MutableList<Hash> =this.entry.dependencies.map(::PijulHash).toMutableList()override fun getTimestamp(): Long = this.entry.date.toEpochSecond()override fun getRoot(): VirtualFile =VirtualFileManager.getInstance().findFileByNioPath(this.root)!!override fun getSubject(): String =if (this.entry.message.isNotEmpty()) ""else this.entry.message.split("\n")[0]override fun getAuthor(): VcsUser =this.entry.authors.firstOrNull()?.let {VcsUserImpl(it.name ?: "", it.email ?: "")} ?: VcsUserImpl("", "")override fun getCommitter(): VcsUser =this.authoroverride fun getAuthorTime(): Long =this.timestampoverride fun getCommitTime(): Long =this.timestampoverride fun getFullMessage(): String =this.entry.messageoverride fun getChanges(): MutableCollection<Change> =this.changeRetriever(this.entry.hash).toMutableList()override fun getChanges(parent: Int): MutableCollection<Change> =this.changeRetriever(this.parents[parent].asString()).toMutableList()}
package com.github.jonathanxd.dracon.pushimport com.intellij.dvcs.push.PushTargetimport com.intellij.openapi.util.NlsSafedata class PijulTarget(@NlsSafe val target: String, @NlsSafe val channel: String) : PushTarget {override fun hasSomethingToPush(): Boolean = trueoverride fun getPresentation(): String = this.targetoverride fun toString(): String = this.getPresentation()}
package com.github.jonathanxd.dracon.pushimport com.github.jonathanxd.dracon.context.PijulVcsContextimport com.github.jonathanxd.dracon.dialog.PijulChangesDialogimport com.github.jonathanxd.dracon.i18n.DraconBundleimport com.github.jonathanxd.dracon.pijul.NonZeroExitStatusCodeimport com.github.jonathanxd.dracon.pijul.SuccessStatusCodeimport com.github.jonathanxd.dracon.pijul.pijulimport com.github.jonathanxd.dracon.repository.PijulRepositoryimport com.intellij.dvcs.push.PushSpecimport com.intellij.dvcs.push.Pusherimport com.intellij.dvcs.push.VcsPushOptionValueimport com.intellij.notification.Notificationimport com.intellij.notification.NotificationGroupimport com.intellij.notification.NotificationTypeimport com.intellij.notification.Notificationsimport com.intellij.openapi.components.serviceimport com.intellij.openapi.project.Projectclass PijulPusher : Pusher<PijulRepository, PijulPushSource, PijulTarget>() {private val PUSH_GROUP =NotificationGroup.createIdWithTitle("Push Changes", DraconBundle.message("push.notification.group.id"))override fun push(pushSpecs: Map<PijulRepository, PushSpec<PijulPushSource, PijulTarget>>,vcsPushOptionValue: VcsPushOptionValue?, force: Boolean) {for ((repository, pijulSpec) in pushSpecs) {val destination: PijulTarget = pijulSpec.targetval source: PijulPushSource = pijulSpec.sourceval project: Project = repository.projectval ctx = project.service<PijulVcsContext>()val push = pijul(project).push(project,ctx.root,source.channel,destination.channel,destination.target) {it.connectAndRetrieveContent()if (it.connected()) {PijulChangesDialog(project, ctx.root, it, it.content(),DraconBundle.message("action.Pijul.Push.text"),DraconBundle.message("push.button.text")).showAndGet()}}if (push.statusCode is SuccessStatusCode) {Notifications.Bus.notify(Notification(PUSH_GROUP,DraconBundle.message("push.notification.title"),DraconBundle.message("push.notification.success"),NotificationType.ERROR,),project)} else {push.statusCode as NonZeroExitStatusCodeNotifications.Bus.notify(Notification(PUSH_GROUP,DraconBundle.message("push.notification.title"),DraconBundle.message("push.notification.failure", push.statusCode.exitCode, push.statusCode.message),NotificationType.INFORMATION,),project)}}}}
package com.github.jonathanxd.dracon.pushimport com.github.jonathanxd.dracon.i18n.DraconBundleimport com.github.jonathanxd.dracon.repository.PijulRepositoryimport com.intellij.dvcs.DvcsUtilimport com.intellij.dvcs.push.PushTargetPanelimport com.intellij.dvcs.push.VcsErrorimport com.intellij.dvcs.push.ui.PushTargetEditorListenerimport com.intellij.dvcs.push.ui.PushTargetTextFieldimport com.intellij.dvcs.push.ui.VcsEditableTextComponentimport com.intellij.openapi.editor.event.DocumentEventimport com.intellij.openapi.editor.event.DocumentListenerimport com.intellij.openapi.ui.ValidationInfoimport com.intellij.openapi.util.NlsSafeimport com.intellij.openapi.util.text.HtmlChunkimport com.intellij.openapi.util.text.StringUtilimport com.intellij.ui.ColoredTreeCellRendererimport com.intellij.util.textCompletion.TextFieldWithCompletionimport com.intellij.ui.SimpleTextAttributesimport java.awt.BorderLayoutclass PijulPushTargetPanel(repository: PijulRepository, source: PijulPushSource, defaultTarget: PijulTarget?) :PushTargetPanel<PijulTarget>() {private val myRepository: PijulRepositoryprivate val myBranchName: @NlsSafe String?private val myDestTargetPanel: TextFieldWithCompletionprivate val myTargetRenderedComponent: VcsEditableTextComponentoverride fun render(renderer: ColoredTreeCellRenderer,isSelected: Boolean,isActive: Boolean,forceRenderedText: String?) {if (forceRenderedText != null) {myDestTargetPanel.text = forceRenderedTextrenderer.append(forceRenderedText)return}val targetText = myDestTargetPanel.textif (StringUtil.isEmptyOrSpaces(targetText)) {renderer.append(DraconBundle.message("action.Pijul.push.enter.remote"),SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES,myTargetRenderedComponent)}myTargetRenderedComponent.setSelected(isSelected)myTargetRenderedComponent.setTransparent(!isActive)myTargetRenderedComponent.render(renderer)}override fun getValue(): PijulTarget {return createValidPushTarget()}private fun createValidPushTarget(): PijulTarget {return PijulTarget(myDestTargetPanel.text, myBranchName!!)}override fun fireOnCancel() {myDestTargetPanel.text = myTargetRenderedComponent.text}override fun fireOnChange() {myTargetRenderedComponent.updateLinkText(myDestTargetPanel.text)}override fun verify(): ValidationInfo? {return if (StringUtil.isEmptyOrSpaces(myDestTargetPanel.text)) {ValidationInfo(VcsError.createEmptyTargetError(DvcsUtil.getShortRepositoryName(myRepository)).text, this)} else null}override fun setFireOnChangeAction(action: Runnable) {// no extra changing components => ignore}override fun addTargetEditorListener(listener: PushTargetEditorListener) {myDestTargetPanel.addDocumentListener(object : DocumentListener {override fun documentChanged(e: DocumentEvent) {listener.onTargetInEditModeChanged(myDestTargetPanel.text)}})}init {layout = BorderLayout()isOpaque = falsemyRepository = repositorymyBranchName = source.channelval targetVariants: List<String> = repository.pijulConfig.remotes.keys.toList()val defaultText = defaultTarget?.presentation ?: ""myTargetRenderedComponent = VcsEditableTextComponent(HtmlChunk.link("", defaultText).toString(), null)myDestTargetPanel = PushTargetTextField(repository.project, targetVariants, defaultText)add(myDestTargetPanel, BorderLayout.CENTER)}}
package com.github.jonathanxd.dracon.pushimport com.github.jonathanxd.dracon.pijulVcsimport com.github.jonathanxd.dracon.repository.PijulRepositoryimport com.github.jonathanxd.dracon.repository.PijulRepositoryManagerimport com.intellij.dvcs.push.OutgoingCommitsProviderimport com.intellij.dvcs.push.PushSupportimport com.intellij.dvcs.push.PushTargetPanelimport com.intellij.dvcs.push.Pusherimport com.intellij.dvcs.repo.RepositoryManagerimport com.intellij.openapi.components.serviceimport com.intellij.openapi.project.Projectimport com.intellij.openapi.vcs.AbstractVcsclass PijulPushSupport(val project: Project) : PushSupport<PijulRepository, PijulPushSource, PijulTarget>() {private val vcs = pijulVcs(project)override fun getVcs(): AbstractVcs = this.vcsoverride fun getPusher(): Pusher<PijulRepository, PijulPushSource, PijulTarget> =PijulPusher()override fun getOutgoingCommitsProvider(): OutgoingCommitsProvider<PijulRepository, PijulPushSource, PijulTarget> =PijulOutgoingChangesProvider()override fun getDefaultTarget(repository: PijulRepository): PijulTarget? {return repository.pijulConfig.defaultRemote?.let {PijulTarget(it, repository.currentBranchName!!)}}override fun getSource(repository: PijulRepository): PijulPushSource {return PijulPushSource(repository.currentBranchName!!)}override fun getRepositoryManager(): RepositoryManager<PijulRepository> =this.project.service<PijulRepositoryManager>()override fun createTargetPanel(repository: PijulRepository,source: PijulPushSource,defaultTarget: PijulTarget?): PushTargetPanel<PijulTarget> =PijulPushTargetPanel(repository, source, defaultTarget)override fun isForcePushAllowed(repo: PijulRepository, target: PijulTarget?): Boolean = falseoverride fun isSilentForcePushAllowed(target: PijulTarget): Boolean = falseoverride fun saveSilentForcePushTarget(target: PijulTarget) {}}
package com.github.jonathanxd.dracon.pushimport com.intellij.dvcs.push.PushSourceclass PijulPushSource(val channel: String) : PushSource {override fun getPresentation(): String = this.channel}
package com.github.jonathanxd.dracon.pushimport com.github.jonathanxd.dracon.log.Authorimport com.intellij.vcs.log.VcsUserimport org.tomlj.Tomlimport java.io.Serializableimport java.time.LocalDateimport java.time.LocalDateTimeimport java.time.ZonedDateTimeimport java.time.format.DateTimeFormatterdata class PijulPushChanges(val entries: List<PijulPushEntry>): Serializable {companion object {const val serialVersionUID = 1L}}data class PijulPushEntry(val hash: String,val dependencies: List<String>,val authors: List<Author>,// TODO: Parse dateval date: ZonedDateTime,val message: String): Serializable {companion object {const val serialVersionUID = 1L}}fun String.parseDate(): ZonedDateTime {val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSSSSSSSS] z")return ZonedDateTime.parse(this, formatter)}fun String.parsePijulPushChanges(): PijulPushChanges {val dependenciesPrefix = " Dependencies: "val authorPrefix = " Author: "val datePrefix = " Date: "val spacePrefix = " "val iter = this.lines().listIterator()val entries = mutableListOf<PijulPushEntry>()while (iter.hasNext()) {val line = iter.next()if (line.startsWith("#") || line.isEmpty()) {continue}if (line[0] != ' ') {val hash = line// Skip empty lineiter.next()var next = iter.next()val dependencies = mutableListOf<String>()if (next.startsWith(dependenciesPrefix)) {dependencies.addAll(next.substring(dependenciesPrefix.length).split(" "))next = iter.next()}val authors = mutableListOf<Author>()if (next.startsWith(authorPrefix)) {val authorsToml = "authors = ${next.substring(authorPrefix.length)}"val toml = Toml.parse(authorsToml)val authorsArray = toml.getArray("authors")for (i in 0 until authorsArray!!.size()) {val authorTable = authorsArray.getTable(i)authors.add(Author(authorTable.getString("name"),authorTable.getString("full_name"),authorTable.getString("email")))}next = iter.next()}val date = if (next.startsWith(datePrefix)) {val date = next.substring(datePrefix.length)next = iter.next()date} else {""}val messages = mutableListOf<String>()if (next.trim().isEmpty()) {if (iter.hasNext()) {next = iter.next()while (next.startsWith(spacePrefix) || next.trim().isEmpty()) {messages += if (next.trim().isEmpty()) {""} else {next.substring(spacePrefix.length)}if (!iter.hasNext()) breaknext = iter.next()}if (next.isNotEmpty() && next[0] != ' ') {iter.previous()}}}entries.add(PijulPushEntry(hash,dependencies,authors,date.parseDate(),messages.joinToString("\n")))}}return PijulPushChanges(entries)}
package com.github.jonathanxd.dracon.pushimport com.github.jonathanxd.dracon.changes.PijulCommittedChangeListimport com.github.jonathanxd.dracon.context.PijulVcsContextimport com.github.jonathanxd.dracon.i18n.DraconBundleimport com.github.jonathanxd.dracon.pijul.SuccessStatusCodeimport com.github.jonathanxd.dracon.pijul.pijulimport com.github.jonathanxd.dracon.repository.PijulRepositoryimport com.intellij.dvcs.push.OutgoingCommitsProviderimport com.intellij.dvcs.push.OutgoingResultimport com.intellij.dvcs.push.PushSpecimport com.intellij.dvcs.push.VcsErrorimport com.intellij.openapi.components.serviceimport com.intellij.openapi.diagnostic.Loggerimport com.intellij.vcs.log.VcsFullCommitDetailsclass PijulOutgoingChangesProvider : OutgoingCommitsProvider<PijulRepository, PijulPushSource, PijulTarget>() {private val logger = Logger.getInstance(PijulOutgoingChangesProvider::class.java)override fun getOutgoingCommits(repository: PijulRepository,pushSpec: PushSpec<PijulPushSource, PijulTarget>,initial: Boolean): OutgoingResult {val project = repository.projectval ctx = project.service<PijulVcsContext>()var content = ""val errors = mutableListOf<VcsError>()val fromChannel = pushSpec.source.channelval toChannel = pushSpec.target.channelval toRemote = pushSpec.target.targetval r = pijul(project).push(project, ctx.root, fromChannel, toChannel, toRemote) {it.connectAndRetrieveContent()if (it.connected()) {content = it.content()it.write("")it.close()} else {errors.add(VcsError(DraconBundle.message("remote.invalid.remote.text", pushSpec.target.target)))content = ""}}if (content.isEmpty()) {return OutgoingResult(emptyList(), errors)} else {try {val parsed = content.parsePijulPushChanges()val commits: List<VcsFullCommitDetails> = parsed.entries.map {PijulVcsFullCommitDetails(ctx.root,project,it) {val changes = mutableListOf<PijulCommittedChangeList>()pijul(project).changes(project, ctx.root, it, -1, {true}) {changes += it}changes.single().changes.toList()}}return OutgoingResult(commits, errors)} catch (t: Throwable) {logger.error(t)}}return OutgoingResult(emptyList(), errors)}}/*Example of changes (this is not hard to parse, but I will not do that now):# Please select the changes to push. The lines that contain just a# valid hash, and no other character (except possibly a newline), will# be pushed.ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQCDependencies: Q7FXTHVUPVAFMNY277C3NFJO3VXLZU5G6C6UYSD5QPURHSG3A7OQC EAGIDXOLFTHZMZ77ZWAM7MVVUBBXJMZD7RZUNBHJPYRFGGKILGVACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-03-31 22:43:40.062881279 UTCImproved support for revisions5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQACDependencies: ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQCAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-01 00:07:39.373781350 UTCAdd support to view files affected by a revisionB43WNBLFFR2UQIH3C6KIZAQTAEQOQM3J3IYLGQMVGJHYOME73OKQCDependencies: 5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-01 17:04:54.758320581 UTC- Add Show History to Pijul menu- Always ignore .idea and .pijul in tracking.- Make findPijul a generic function to allow to find editor-server.- Only show one revision for directories.- Add `Hunk::resolvePath(Path)` to resolve the affected file to a Java NIO Path.- Fix StringOutOfBounds in Change Parsering Algorithm- Use editor-server instead of copie for interfacing with `pijul record` file.- Fix FileStatus provider not returning correctly for untracked files.- Add CommittedChangesProvider for Pijul.Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJACDependencies: B43WNBLFFR2UQIH3C6KIZAQTAEQOQM3J3IYLGQMVGJHYOME73OKQCAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-02 21:31:47.581509792 UTCRemove use of coroutines, which was blocking IntelliJ UI in larger repositoriesImprovements for bigger repositories, now Dracon caches the changes that happened in a revision in a file, so everytime Dracon needs to query the changes of a revision, it loads directly from memory instead of doing a full-scan in Pijul repository. For tiny projects it is not a problem, but for medium ones it takes more than five minutes to scan the entire repository (and it was tested with a repo of only 700 records, however there was changes that had more than 60.000 lines).The cache file is saved in IntelliJ Data Path (project specific) and is compressed with gzip, so it will not use so much disk space (the cost worths the gains).ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QCDependencies: Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-03 03:18:36.900275901 UTCMore caches, better and generic cache code.Now Dracon listen to file changes to drop cached data.Implemented caches:- File contents in specific revision (never dropped)- Pijul ls and Pijul diff results- File Revision and File changes by patch- some others..Dracon is incredible fast now, but still will take some time for bigger repos.2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWACDependencies: ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QCAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-04 03:15:58.713132084 UTCAdd auto installation support and cache content of ContentRevision37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6ACDependencies: A7JOR7M3BUKXYMMAR43IK4GXFXGI33HM6H6LZHDES3HWW6GYFAYAC G54TB4QZZ6OYC2KZTB7KUVW3NJ6VASH7WPNFU2IATPZWM3POIRNQC 2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-04 12:07:50.967878750 UTCImproved caching code a lotA7IL6I3VCB3F3QMYQFPXBL33DN5XDGGQPZIBZRHYSQBSIUBBFQJQCDependencies: 37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6ACAuthor: [{ name = "Jonathan", full_name = "Jonathan H. R. Lopes", email = "jhrldev@gmail.com" }]Date: 2021-04-04 18:38:01.065118605 UTCMore files to support .ignore*/
@RequiresBackgroundThreadfun push(project: Project, root: Path, editorServerConsumer: (EditorServer) -> Unit): PijulOperationResult<String>@RequiresBackgroundThreadfun push(project: Project, root: Path,fromChannel: String? = null,toChannel: String? = null,repository: String? = null,editorServerConsumer: (EditorServer) -> Unit): PijulOperationResult<String>
package com.github.jonathanxd.dracon.logimport com.intellij.vcs.log.Hashclass PijulHash(val hash: String) : Hash {override fun asString(): String = this.hashoverride fun toShortString(): String = this.hash.substring(0, 10)}
package com.github.jonathanxd.dracon.dialogimport com.github.jonathanxd.dracon.completion.PijulRecordFileTextCompletionProviderimport com.github.jonathanxd.dracon.editor.EditorServerimport com.github.jonathanxd.dracon.i18n.DraconBundleimport com.github.jonathanxd.dracon.pijul.NonZeroExitStatusCodeimport com.github.jonathanxd.dracon.pijul.SuccessStatusCodeimport com.github.jonathanxd.dracon.pijul.pijulimport com.intellij.CommonBundleimport com.intellij.ide.IdeBundleimport com.intellij.lang.Languageimport com.intellij.notification.Notificationimport com.intellij.notification.NotificationGroupimport com.intellij.notification.NotificationTypeimport com.intellij.notification.Notificationsimport com.intellij.openapi.application.ApplicationManagerimport com.intellij.openapi.editor.Documentimport com.intellij.openapi.editor.ex.EditorEximport com.intellij.openapi.fileTypes.FileTypeRegistryimport com.intellij.openapi.project.Projectimport com.intellij.openapi.ui.DialogEarthquakeShakerimport com.intellij.openapi.ui.DialogWrapperimport com.intellij.openapi.ui.DialogWrapper.DialogWrapperActionimport com.intellij.openapi.ui.DialogWrapper.IdeModalityTypeimport com.intellij.openapi.ui.ValidationInfoimport com.intellij.openapi.ui.popup.JBPopupFactoryimport com.intellij.openapi.wm.IdeFocusManagerimport com.intellij.openapi.wm.WindowManagerimport com.intellij.psi.PsiFileimport com.intellij.ui.EditorTextFieldimport com.intellij.ui.LanguageTextFieldimport com.intellij.ui.TextFieldWithAutoCompletionimport com.intellij.ui.TextFieldWithAutoCompletionListProviderimport com.intellij.util.containers.ContainerUtilimport com.intellij.util.textCompletion.TextCompletionUtilimport org.jetbrains.annotations.Nullableimport java.awt.*import java.awt.event.*import java.beans.PropertyChangeEventimport java.beans.PropertyChangeListenerimport java.lang.Booleanimport java.nio.file.Pathimport javax.swing.*open class PijulExpertRecordDialog(val project: Project,val vcsRoot: Path,val text: String) : DialogWrapper(project, true) {private val EXPERT_MODE_GROUP =NotificationGroup.createIdWithTitle("Expert Mode", DraconBundle.message("expert.mode.notification.group.id"))init {init()title = DraconBundle.message("action.Pijul.ExpertRecord.text")}//private lateinit var editor: EditorTextField//private lateinit var field: TextFieldWithAutoCompletion<String>private lateinit var editor: CustomEditorFieldoverride fun createCenterPanel(): JComponent {val dialogPanel = JPanel(BorderLayout())val tomlLanguage = Language.findLanguageByID("TOML")val ext = FileTypeRegistry.getInstance().getFileTypeByExtension("toml")val doc = LanguageTextField.createDocument(this.text,tomlLanguage,this.project,RecordDocumentCreator())editor = CustomEditorField(tomlLanguage, project, this.text)/*val field = TextFieldWithAutoCompletion(this.project, Provider(), true, this.text)field.setOneLineMode(false)field.isViewer = false*///editor = EditorTextField(doc, this.project, ext, false, false)editor.preferredSize = Dimension(800, 600)editor.setOneLineMode(false)editor.isViewer = falseeditor.isVisible = trueeditor.isEnabled = true//field.preferredSize = Dimension(800, 600)dialogPanel.add(editor, BorderLayout.CENTER)return dialogPanel}override fun createActions(): Array<Action> {return arrayOf(RecordAction(), this.cancelAction)}override fun doOKAction() {if (record.statusCode is SuccessStatusCode) {val hash = record.result!!.substring("Hash:".length).trim()Notifications.Bus.notify(Notification(EXPERT_MODE_GROUP,DraconBundle.message("expert.mode.notification.title"),DraconBundle.message("expert.mode.notification.success", hash),NotificationType.ERROR,),this.project)} else {record.statusCode as NonZeroExitStatusCodeNotifications.Bus.notify(Notification(EXPERT_MODE_GROUP,DraconBundle.message("expert.mode.notification.title"),DraconBundle.message("expert.mode.notification.failure", record.statusCode.exitCode, record.statusCode.message),NotificationType.INFORMATION,),this.project)super.doOKAction()}protected inner class RecordAction() : DialogWrapper.DialogWrapperAction(DraconBundle.message("expert.mode.button.record")) {override fun doAction(e: ActionEvent?) {val infoList: List<ValidationInfo> = doValidateAll()if (infoList.isNotEmpty()) {val info = infoList[0]if (info.component != null && info.component!!.isVisible) {IdeFocusManager.getInstance(null).requestFocus(info.component!!, true)}updateErrorInfo(infoList)startTrackingValidation()if (ContainerUtil.exists(infoList) { info1: ValidationInfo -> !info1.okEnabled }) return}doOKAction()}init {addPropertyChangeListener { evt: PropertyChangeEvent ->if (NAME == evt.propertyName) {repaint()}}}}class Provider : TextFieldWithAutoCompletionListProvider<String>(listOf("author", "[[authors]]", "authors", "name", "full_name", "email")) {override fun getLookupString(item: String): String {return item}}class RecordDocumentCreator : TextCompletionUtil.DocumentWithCompletionCreator(TextFieldWithAutoCompletion.StringsCompletionProvider(listOf("author", "[[authors]]", "authors", "name", "full_name", "email"),null),true)}class CustomEditorField(language: Language?, project: Project, s: String) : LanguageTextField(language, project, s, PijulExpertRecordDialog.RecordDocumentCreator(), false) {override fun createEditor(): EditorEx {val editor = super.createEditor()editor.setVerticalScrollbarVisible(true)editor.setHorizontalScrollbarVisible(true)editor.setCaretEnabled(true)editor.isViewer = falseeditor.isOneLineMode = falseval settings = editor.settingssettings.isLineNumbersShown = truesettings.isAutoCodeFoldingEnabled = truesettings.isFoldingOutlineShown = truesettings.isAllowSingleLogicalLineFolding = truesettings.isRightMarginShown=truereturn editor}}}*/this.editorServer.write(this.editor.text)this.editorServer.close()/*val record = pijul(this.project).recordFromString(this.project, this.vcsRoot, this.editor.text)val editorServer: EditorServer,
package com.github.jonathanxd.dracon.dialogimport com.github.jonathanxd.dracon.editor.EditorServerimport com.github.jonathanxd.dracon.i18n.DraconBundleimport com.intellij.lang.Languageimport com.intellij.notification.NotificationGroupimport com.intellij.openapi.editor.ex.EditorEximport com.intellij.openapi.fileTypes.FileTypeRegistryimport com.intellij.openapi.project.Projectimport com.intellij.openapi.ui.DialogWrapperimport com.intellij.openapi.ui.ValidationInfoimport com.intellij.openapi.util.NlsContextsimport com.intellij.openapi.util.NlsContexts.DialogTitleimport com.intellij.openapi.util.NlsContexts.Buttonimport com.intellij.openapi.wm.IdeFocusManagerimport com.intellij.ui.LanguageTextFieldimport com.intellij.ui.TextFieldWithAutoCompletionimport com.intellij.ui.TextFieldWithAutoCompletionListProviderimport com.intellij.util.containers.ContainerUtilimport com.intellij.util.textCompletion.TextCompletionUtilimport java.awt.*import java.awt.event.*import java.beans.PropertyChangeEventimport java.nio.file.Pathimport javax.swing.*open class PijulChangesDialog(val project: Project,val vcsRoot: Path,val editorServer: EditorServer,val text: String,@DialogTitle val title_: String,@Button val button_: String) : DialogWrapper(project, true) {init {init()title = title_}private lateinit var editor: CustomEditorFieldoverride fun createCenterPanel(): JComponent {val dialogPanel = JPanel(BorderLayout())val tomlLanguage = Language.findLanguageByID("TOML")editor = CustomEditorField(tomlLanguage, project, this.text)editor.preferredSize = Dimension(800, 600)editor.setOneLineMode(false)editor.isViewer = falseeditor.isVisible = trueeditor.isEnabled = truedialogPanel.add(editor, BorderLayout.CENTER)return dialogPanel}override fun createActions(): Array<Action> {return arrayOf(RecordAction(), this.cancelAction)}override fun doOKAction() {this.editorServer.write(this.editor.text)this.editorServer.close()super.doOKAction()}protected inner class RecordAction() : DialogWrapper.DialogWrapperAction(button_) {override fun doAction(e: ActionEvent?) {val infoList: List<ValidationInfo> = doValidateAll()if (infoList.isNotEmpty()) {val info = infoList[0]if (info.component != null && info.component!!.isVisible) {IdeFocusManager.getInstance(null).requestFocus(info.component!!, true)}updateErrorInfo(infoList)startTrackingValidation()if (ContainerUtil.exists(infoList) { info1: ValidationInfo -> !info1.okEnabled }) return}doOKAction()}init {addPropertyChangeListener { evt: PropertyChangeEvent ->if (NAME == evt.propertyName) {repaint()}}}}class Provider : TextFieldWithAutoCompletionListProvider<String>(listOf("author", "[[authors]]", "authors", "name", "full_name", "email")) {override fun getLookupString(item: String): String {return item}}class RecordDocumentCreator : TextCompletionUtil.DocumentWithCompletionCreator(TextFieldWithAutoCompletion.StringsCompletionProvider(listOf("author", "[[authors]]", "authors", "name", "full_name", "email"),null),true)}class CustomEditorField(language: Language?, project: Project, s: String) : LanguageTextField(language, project, s, PijulChangesDialog.RecordDocumentCreator(), false) {override fun createEditor(): EditorEx {val editor = super.createEditor()editor.setVerticalScrollbarVisible(true)editor.setHorizontalScrollbarVisible(true)editor.setCaretEnabled(true)editor.isViewer = falseeditor.isOneLineMode = falseval settings = editor.settingssettings.isLineNumbersShown = truesettings.isAutoCodeFoldingEnabled = truesettings.isFoldingOutlineShown = truesettings.isAllowSingleLogicalLineFolding = truesettings.isRightMarginShown=truereturn editor}}
package com.github.jonathanxd.dracon.configimport com.intellij.ide.plugins.PluginManagerimport com.intellij.openapi.diagnostic.Loggerimport org.tomlj.Tomlimport java.nio.file.Filesimport java.nio.file.Pathclass PijulConfig(val root: Path) {private val logger = Logger.getInstance(PijulConfig::class.java)var currentChannel: String = ""var extraDependencies: List<String> = mutableListOf()var defaultRemote: String? = nullvar remotes: Map<String, String> = mutableMapOf()init {this.load(root)}fun load(root: Path) {val configPath = root.resolve(".pijul").resolve("config")if (!Files.exists(configPath)) {this.logger.error("Could not find $configPath.")return}val toml = Toml.parse(configPath)if (toml.hasErrors()) {this.logger.error("Errors found in .pijul/config TOML file.")for (error in toml.errors()) {this.logger.error(error)}}this.currentChannel = toml.getString("current_channel")!!val exDps = toml.getArray("extra_dependencies")!!this.extraDependencies = List(exDps.size()) {exDps.getString(it)}this.defaultRemote = toml.getString("default_remote")this.remotes = toml.getTable("remotes")?.toMap() as? Map<String, String> ?: emptyMap()}}
this.doExecutionWithMapper("file_status_from_ls", this.createExecPijulOperation(project, rootPath, listOf("ls"), log = false)) {val trackedFiles = it.split("\n")
this.doExecutionWithMapper("file_status_from_ls",this.createExecPijulOperation(project, rootPath, listOf("ls"), log = false)) {val trackedFiles = it.split("\n")
val fPath = Paths.get(VcsUtil.getFilePath(file.path).path).relativeTo(rootPath).toString()if (trackedFiles.contains(fPath)) {FileStatus.NOT_CHANGED} else {FileStatus.UNKNOWN
val fPath = Paths.get(VcsUtil.getFilePath(file.path).path).relativeTo(rootPath).toString()if (trackedFiles.contains(fPath)) {FileStatus.NOT_CHANGED} else {FileStatus.UNKNOWN}
this.doExecutionWithMapper("file_status_from_ls", this.createExecPijulOperation(project, root, listOf("ls"), log = false)) {
this.doExecutionWithMapper("file_status_from_ls",this.createExecPijulOperation(project, root, listOf("ls"), log = false)) {
this.doExecutionWithMapper("file_status_from_ls", this.createExecPijulOperation(project, root, listOf("ls"), log = false)) {
this.doExecutionWithMapper("file_status_from_ls",this.createExecPijulOperation(project, root, listOf("ls"), log = false)) {
return this.doExecutionWithMapper("tracked_files_from_ls", this.createExecPijulOperation(project, root, listOf("ls"), log = false)) {it.split("\n").map {root.resolve(it)}
return this.doExecutionWithMapper("tracked_files_from_ls",this.createExecPijulOperation(project, root, listOf("ls"), log = false)) {it.split("\n").map {root.resolve(it)
return PijulOperationResult("rollbackTo_${hash}", NonZeroExitStatusCode(-1, "Could not find hash $hash in Pijul log."), false)
return PijulOperationResult("rollbackTo_${hash}",NonZeroExitStatusCode(-1, "Could not find hash $hash in Pijul log."),false)
it}}override fun push(project: Project,root: Path,editorServerConsumer: (EditorServer) -> Unit): PijulOperationResult<String> {val arguments = mutableListOf("push")val operation = this.createPainlessExecPijulWithEditorServer(this.project,root,arguments,editorServerConsumer)return this.doExecutionWithMapper("push", operation) {
override fun push(project: Project,root: Path,fromChannel: String?,toChannel: String?,repository: String?,editorServerConsumer: (EditorServer) -> Unit): PijulOperationResult<String> {val arguments = mutableListOf("push")if (fromChannel != null) {arguments.add("--from-channel")arguments.add(fromChannel)}if (toChannel != null) {arguments.add("--to-channel")arguments.add(toChannel)}if (repository != null) {arguments.add(repository)}val operation = this.createPainlessExecPijulWithEditorServer(this.project,root,arguments,editorServerConsumer)return this.doExecutionWithMapper("push", operation) {it}}
}override fun changes(project: Project,root: Path,revision: String?,maxCount: Int,filter: (PijulLogEntry) -> Boolean,consumer: (PijulCommittedChangeList) -> Unit): PijulOperationResult<Unit> {val allRevisions = pijul(this.project).allRevisions(this.project, root).result!!val log = this.log(this.project, root)return log.result?.entries?.filter {filter(it)}?.filter {revision == null || it.revision.hash == revision}?.map { entry ->PijulCommittedChangeList(entry.message.trimMiddle(20),entry.message,entry.authors.firstOrNull()?.name ?: "No author",Date.from(entry.date.toInstant()),entry.hunks.filterIsInstance<HunkWithPath>().groupBy { it.resolvePath(root) }.map { (p, hunks) ->val hunk = hunks.firstOrNull { it is EditHunk }?: hunks.firstOrNull { it is ReplacementHunk }?: hunks.firstOrNull { it is FileDelHunk }?: hunks.firstOrNull { it is FileAddHunk }?: hunks.first()val beforeRevision =if (hunk is FileAddHunk) nullelse findARevisionBefore(entry.changeHash, allRevisions)?.let {PijulContentRevision(root,hunk.resolvePath(root),it,this.project)}val afterRevision =if (hunk is FileDelHunk) nullelse PijulContentRevision(root,hunk.resolvePath(root),entry.revision,this.project)Change(beforeRevision,afterRevision,hunk.status)}.toMutableList(),entry.revision,false,pijulVcs(this.project))}?.let { if (maxCount == -1) it else it.take(maxCount) }?.forEach {consumer(it)}?.let {PijulOperationResult("changes", SuccessStatusCode, Unit)} ?: PijulOperationResult("changes", log.statusCode, Unit)}fun findARevisionBefore(current: String, allRevisions: List<PijulRevisionNumber>): PijulRevisionNumber? {for (i in allRevisions.indices) {if (current == allRevisions[i].hash) {return if (i + 1 >= allRevisions.size) {null} else {allRevisions[i + 1]}}}return null
val change = this.doExecutionWithMapper("diff", this.createExecPijulOperation(project, rootPath, listOf("diff"))) {
val change =this.doExecutionWithMapper("diff", this.createExecPijulOperation(project, rootPath, listOf("diff"))) {if (it.isEmpty()) nullelse it.parseChange("")}return change}override fun diff(project: Project, root: Path): PijulOperationResult<PijulLogEntry> {val change = this.doExecutionWithMapper("diff", this.createExecPijulOperation(project, root, listOf("diff"))) {
fun <T> doExecutionWithMapper(name: String,execution: PijulExecution,regularStreamStringMapper: (String) -> T?): PijulOperationResult<T> {
fun <T> doExecutionWithMapper(name: String,execution: PijulExecution,regularStreamStringMapper: (String) -> T?): PijulOperationResult<T> {
fun <T> doExecutionWithMapperEvenFailed(name: String,execution: PijulExecution,regularStreamStringMapper: (String) -> T?): PijulOperationResult<T> {
fun <T> doExecutionWithMapperEvenFailed(name: String,execution: PijulExecution,regularStreamStringMapper: (String) -> T?): PijulOperationResult<T> {
private fun createExecPijulOperation(project: Project,dir: Path,args: List<String>,log: Boolean = true): PijulExecution {
private fun createExecPijulOperation(project: Project,dir: Path,args: List<String>,log: Boolean = true): PijulExecution {
private fun createPainlessExecPijulOperation(project: Project,dir: Path,args: List<String>): PijulExecution {
private fun createPainlessExecPijulOperation(project: Project,dir: Path,args: List<String>): PijulExecution {
private fun <K: Any> createPainlessExecPijulOperationWithCache(project: Project,dir: Path,args: List<String>,key: K): PijulExecution {
private fun <K : Any> createPainlessExecPijulOperationWithCache(project: Project,dir: Path,args: List<String>,key: K): PijulExecution {
private fun createPainlessExecPijulWithCopieOperation(project: Project,dir: Path,copiePath: Path,copieMode: CopieMode,args: List<String>): PijulExecution {
private fun createPainlessExecPijulWithCopieOperation(project: Project,dir: Path,copiePath: Path,copieMode: CopieMode,args: List<String>): PijulExecution {
private fun createPainlessExecPijulWithEditorServer(project: Project,dir: Path,args: List<String>,editorServerConsumer: (EditorServer) -> Unit): PijulExecution {
private fun createPainlessExecPijulWithEditorServer(project: Project,dir: Path,args: List<String>,editorServerConsumer: (EditorServer) -> Unit): PijulExecution {
class PijulCommittedChangesProvider(val project: Project) : CommittedChangesProvider<CommittedChangeList, ChangeBrowserSettings> {
class PijulCommittedChangesProvider(val project: Project) :CommittedChangesProvider<CommittedChangeList, ChangeBrowserSettings> {
val channel = pijul(this.project).channel(this.project, ctx.root).result?.channels?.firstOrNull { it.current }?.name ?: "unknown"
val channel =pijul(this.project).channel(this.project, ctx.root).result?.channels?.firstOrNull { it.current }?.name?: "unknown"
}?.filter {revision == null || it.revision.hash == revision.asString()}?.map { entry ->PijulCommittedChangeList(entry.message.trimMiddle(20),entry.message,entry.authors.firstOrNull()?.name ?: "No author",Date.from(entry.date.toInstant()),entry.hunks.filterIsInstance<HunkWithPath>().groupBy { it.resolvePath(ctx.root) }.map { (p, hunks) ->val hunk = hunks.firstOrNull { it is EditHunk }?: hunks.firstOrNull { it is ReplacementHunk }?: hunks.firstOrNull { it is FileDelHunk }?: hunks.firstOrNull { it is FileAddHunk }?: hunks.first()val beforeRevision =if (hunk is FileAddHunk) nullelse findARevisionBefore(entry.changeHash, allRevisions)?.let {PijulContentRevision(ctx.root,hunk.resolvePath(ctx.root),it,this.project)}val afterRevision =if (hunk is FileDelHunk) nullelse PijulContentRevision(ctx.root,hunk.resolvePath(ctx.root),entry.revision,this.project)Change(beforeRevision,afterRevision,hunk.status)}.toMutableList(),entry.revision,false,pijulVcs(this.project))}?.let { if (maxCount == -1) it else it.take(maxCount) }?.forEach {
}) {
fun findARevisionBefore(current: String, allRevisions: List<PijulRevisionNumber>): PijulRevisionNumber? {for (i in allRevisions.indices) {if (current == allRevisions[i].hash) {return if (i + 1 >= allRevisions.size) {null} else {allRevisions[i + 1]}}}return null}
return this.cache.queryOrLoadAsync(fileRev) {loadStateInRevision(rev.hash,this.project,
return this.cache.queryOrLoadAsyncExpanded(fileRev) {val revisions = loadStateInEveryRevisionForAllFiles(listOf(rev.hash),project,
file).toByteArray(Charsets.UTF_8)
EmptyProgressIndicator())val revisionsForHash = revisions[rev.hash]!!val stringKeys = revisionsForHash.mapKeys { (k, _) -> k.filePathAsString() }stringKeys[it.filePath]!! to stringKeys.map { (k, v) -> FileRevisionRef(k, rev.hash) to v }
this.inMemory[key] = computeEntrythis.manager.write(this.inMemory)computeEntry} finally {this.lock.unlock()}.value}, this.updateExecutor)}}fun queryOrLoadAsyncExpanded(key: K, compute: (K) -> Pair<V, List<Pair<K, V>>>): CompletableFuture<V> {if (this.inMemory.containsKey(key)) {return CompletableFuture.completedFuture(this.inMemory[key]!!.value)} else {return CompletableFuture.supplyAsync({this.lock.lock()try {if (this.inMemory.containsKey(key)) {return@supplyAsync this.inMemory[key]!!.value}val instant = Instant.now()val computed = compute(key)val computeEntry = CachedValue(instant, computed.first)
package com.github.jonathanxd.dracon.actionsimport com.github.jonathanxd.dracon.dialog.PijulChangesDialogimport com.github.jonathanxd.dracon.i18n.DraconBundleimport com.github.jonathanxd.dracon.pijul.NonZeroExitStatusCodeimport com.github.jonathanxd.dracon.pijul.SuccessStatusCodeimport com.github.jonathanxd.dracon.pijul.pijulimport com.intellij.notification.Notificationimport com.intellij.notification.NotificationGroupimport com.intellij.notification.NotificationTypeimport com.intellij.notification.Notificationsimport com.intellij.openapi.actionSystem.AnActionEventimport com.intellij.openapi.project.DumbAwareActionimport com.intellij.openapi.vcs.ProjectLevelVcsManagerclass PijulPushRecord : DumbAwareAction() {private val PUSH_GROUP =NotificationGroup.createIdWithTitle("Push Changes", DraconBundle.message("push.notification.group.id"))override fun actionPerformed(e: AnActionEvent) {val project = e.project!!val vcsManager = ProjectLevelVcsManager.getInstance(project)val root = vcsManager.allVcsRoots.first().path.toNioPath()val record = pijul(project).push(project, root) {it.connectAndRetrieveContent()if (it.connected()) {PijulChangesDialog(project, root, it, it.content(),DraconBundle.message("action.Pijul.Push.text"),DraconBundle.message("push.button.text")).showAndGet()}}if (record.statusCode is SuccessStatusCode) {Notifications.Bus.notify(Notification(PUSH_GROUP,DraconBundle.message("push.notification.title"),DraconBundle.message("push.notification.success"),NotificationType.ERROR,),project)} else {record.statusCode as NonZeroExitStatusCodeNotifications.Bus.notify(Notification(PUSH_GROUP,DraconBundle.message("push.notification.title"),DraconBundle.message("push.notification.failure", record.statusCode.exitCode, record.statusCode.message),NotificationType.INFORMATION,),project)}}}
/*if (recordString.result != null) {val toml = FileTypeRegistry.getInstance().getFileTypeByExtension("toml")//val editor = EditorTextField(recordString.result, this.project, )*//*val psiFile = PsiDocumentManager.getInstance(editor.getProject()).getPsiFile(editor.getDocument())val element = psiFile!!.findElementAt(editor.getCaretModel().getOffset())val code: PsiExpressionCodeFragment = JavaCodeFragmentFactory.getInstance(editor.getProject()).createExpressionCodeFragment("", element, null, true)val document: Document? = PsiDocumentManager.getInstance(editor.getProject()).getDocument(code)val myInput = EditorTextField(document, editor.getProject(), JavaFileType.INSTANCE)*//*PijulExpertRecordDialog(project, root, recordString.result).showAndGet()*//*FileEditorManager.getInstance(project).openTextEditor(OpenFileDescriptor(project, LightVirtualFile("record", toml, recordString.result)),true)*//*}*/