~wegtam/smederee

Showing details for patch 60d66b783ffd470f9de74cd766e1710b3e27ef94.
2025-03-28 (Fri), 6:04 PM - Jens Grassel - 60d66b783ffd470f9de74cd766e1710b3e27ef94

vcs: Allow choosing darcs patch format for new repos.

- add DarcsPatchFormat
- include in form for new repository
- adjust code in VcsRepositoryRoutes
Summary of changes
5 files modified with 95 lines added and 10 lines removed
  • modules/darcs/src/main/scala/de/smederee/darcs/DarcsCommands.scala with 36 added and 0 removed lines
  • modules/hub/src/main/resources/messages.properties with 2 added and 0 removed lines
  • modules/hub/src/main/scala/de/smederee/hub/NewVcsRepositoryForm.scala with 42 added and 9 removed lines
  • modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala with 3 added and 1 removed lines
  • modules/hub/src/main/twirl/de/smederee/hub/views/createRepository.scala.html with 12 added and 0 removed lines
diff -rN -u old-smederee/modules/darcs/src/main/scala/de/smederee/darcs/DarcsCommands.scala new-smederee/modules/darcs/src/main/scala/de/smederee/darcs/DarcsCommands.scala
--- old-smederee/modules/darcs/src/main/scala/de/smederee/darcs/DarcsCommands.scala	2025-04-01 12:44:03.123496901 +0000
+++ new-smederee/modules/darcs/src/main/scala/de/smederee/darcs/DarcsCommands.scala	2025-04-01 12:44:03.123496901 +0000
@@ -45,6 +45,42 @@
 
 }
 
+/** The patch format darcs is using inside a repository.
+  *
+  * @param option
+  *   The command line option that must be passed to the darcs binary to enable the format.
+  */
+enum DarcsPatchFormat(val option: String) {
+
+    /** Older darcs patch format (for compatibility). Not recommended due to potential exponential merge problem.
+      */
+    case V1 extends DarcsPatchFormat(option = "--darcs-1")
+
+    /** Standard darcs patch format as of time of this writing.
+      */
+    case V2 extends DarcsPatchFormat(option = "--darcs-2")
+
+    /** New darcs patch format considered stable but not yet recommended as of time of this writing.
+      */
+    case V3 extends DarcsPatchFormat(option = "--darcs-3")
+}
+
+object DarcsPatchFormat {
+    given Eq[DarcsPatchFormat] = Eq.fromUniversalEquals
+
+    // Short hand for the default patch format.
+    val Default = DarcsPatchFormat.V2
+
+    /** Return the darcs patch format type matching the given command line option.
+      *
+      * @param option
+      *   The command line option that must be passed to the darcs binary to enable the format.
+      * @return
+      *   An option to the matching darcs patch format type.
+      */
+    def fromOption(option: String): Option[DarcsPatchFormat] = DarcsPatchFormat.values.find(_.option === option)
+}
+
 /** Wrapper for output generated by an external darcs command.
   *
   * @param exitValue
diff -rN -u old-smederee/modules/hub/src/main/resources/messages.properties new-smederee/modules/hub/src/main/resources/messages.properties
--- old-smederee/modules/hub/src/main/resources/messages.properties	2025-04-01 12:44:03.123496901 +0000
+++ new-smederee/modules/hub/src/main/resources/messages.properties	2025-04-01 12:44:03.123496901 +0000
@@ -83,6 +83,8 @@
 form.create-repo.description=Description
 form.create-repo.description.placeholder=
 form.create-repo.description.help=An optional short description of your repo / project.
+form.create-repo.darcs-patch-format=Darcs patch format
+form.create-repo.darcs-patch-format.help=The internal patch format to be used for the repository. Currently V2 is the default and recommended.
 form.create-repo.tickets-enabled=Ticket tracking
 form.create-repo.tickets-enabled.help=Enable ticket tracking support to be able to use tickets with labels and milestones for organising the development process if needed.
 form.create-repo.website=Website
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/NewVcsRepositoryForm.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/NewVcsRepositoryForm.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/NewVcsRepositoryForm.scala	2025-04-01 12:44:03.123496901 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/NewVcsRepositoryForm.scala	2025-04-01 12:44:03.123496901 +0000
@@ -8,6 +8,7 @@
 
 import cats.data.*
 import cats.syntax.all.*
+import de.smederee.darcs.DarcsPatchFormat
 import de.smederee.hub.forms.*
 import de.smederee.hub.forms.types.*
 import org.http4s.Uri
@@ -26,21 +27,25 @@
   *   A flag indicating if ticket tracking support via the ticket service is enabled for this repository.
   * @param website
   *   An optional uri pointing to a website related to the repository / project.
+  * @param darcsPatchFormat
+  *   The patch format that shall be used when initialising the new repository.
   */
 final case class NewVcsRepositoryForm(
     name: VcsRepositoryName,
     isPrivate: Boolean,
     description: Option[VcsRepositoryDescription],
     ticketsEnabled: Boolean,
-    website: Option[Uri]
+    website: Option[Uri],
+    darcsPatchFormat: DarcsPatchFormat
 )
 
 object NewVcsRepositoryForm extends FormValidator[NewVcsRepositoryForm] {
-    val fieldDescription: FormField    = FormField("description")
-    val fieldIsPrivate: FormField      = FormField("is_private")
-    val fieldName: FormField           = FormField("name")
-    val fieldTicketsEnabled: FormField = FormField("tickets_enabled")
-    val fieldWebsite: FormField        = FormField("website")
+    val fieldDescription: FormField      = FormField("description")
+    val fieldIsPrivate: FormField        = FormField("is_private")
+    val fieldName: FormField             = FormField("name")
+    val fieldDarcsPatchFormat: FormField = FormField("patch_format")
+    val fieldTicketsEnabled: FormField   = FormField("tickets_enabled")
+    val fieldWebsite: FormField          = FormField("website")
 
     override def validate(data: Map[String, Chain[String]]): ValidatedNec[FormErrors, NewVcsRepositoryForm] = {
         val name = data
@@ -89,9 +94,37 @@
                         }
             }
             .leftMap(es => NonEmptyChain.of(Map(fieldWebsite -> es.toList)))
-        (name, privateFlag, description, ticketsEnabledFlag, website).mapN {
-            case (validName, isPrivate, validDescription, ticketsEnabled, validWebsite) =>
-                NewVcsRepositoryForm(validName, isPrivate, validDescription, ticketsEnabled, validWebsite)
+        val darcsPatchFormat = data
+            .get(fieldDarcsPatchFormat)
+            .filter(_.nonEmpty)
+            .fold(DarcsPatchFormat.Default.validNec)(
+                _.headOption
+                    .flatMap(DarcsPatchFormat.fromOption)
+                    .fold(FormFieldError("Invalid darcs patch format!").invalidNec)(_.validNec)
+            )
+            .leftMap(es => NonEmptyChain.of(Map(fieldDarcsPatchFormat -> es.toList)))
+        (name, privateFlag, description, ticketsEnabledFlag, website, darcsPatchFormat).mapN {
+            case (validName, isPrivate, validDescription, ticketsEnabled, validWebsite, patchFormat) =>
+                NewVcsRepositoryForm(validName, isPrivate, validDescription, ticketsEnabled, validWebsite, patchFormat)
         }
     }
+
+    extension (form: NewVcsRepositoryForm) {
+
+        /** Convert the form class into a stringified map which is used as underlying data type for form handling in the
+          * twirl templating library.
+          *
+          * @return
+          *   A stringified map containing the data of the form.
+          */
+        def toMap: Map[String, Chain[String]] =
+            Map(
+                fieldDescription.toString -> form.description.map(_.toString).fold(Chain.empty)(desc => Chain(desc)),
+                fieldIsPrivate.toString   -> Chain(form.isPrivate.toString),
+                fieldName.toString        -> Chain(form.name.toString),
+                fieldDarcsPatchFormat.toString -> Chain(form.darcsPatchFormat.option),
+                fieldTicketsEnabled.toString   -> Chain(form.ticketsEnabled.toString),
+                fieldWebsite.toString          -> form.website.map(_.toString).fold(Chain.empty)(url => Chain(url))
+            )
+    }
 }
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala	2025-04-01 12:44:03.123496901 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala	2025-04-01 12:44:03.123496901 +0000
@@ -1319,7 +1319,9 @@
                                                 VcsType.Darcs,
                                                 newVcsRepositoryForm.website
                                             )
-                                            output <- darcs.initialize(directory)(newRepo.name.toString)(Chain.empty)
+                                            output <- darcs.initialize(directory)(newRepo.name.toString)(
+                                                Chain(newVcsRepositoryForm.darcsPatchFormat.option)
+                                            )
                                             _ <-
                                                 if (output.exitValue === 0)
                                                     for {
diff -rN -u old-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/createRepository.scala.html new-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/createRepository.scala.html
--- old-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/createRepository.scala.html	2025-04-01 12:44:03.123496901 +0000
+++ new-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/createRepository.scala.html	2025-04-01 12:44:03.127496895 +0000
@@ -1,3 +1,4 @@
+@import de.smederee.darcs.DarcsPatchFormat
 @import de.smederee.hub.*
 @import de.smederee.hub.forms.types.*
 @import de.smederee.hub.views.html.forms.*
@@ -63,6 +64,17 @@
                   <span class="pure-form-message" id="@{fieldWebsite}.help">@Messages("form.create-repo.website.help")</span>
                   @renderFormErrors(fieldWebsite, formErrors)
                 </div>
+                <div class="pure-control-group">
+                  <label for="@{fieldDarcsPatchFormat}">@Messages("form.create-repo.darcs-patch-format")</label>
+                  <select class="pure-input-1-2" id="@{fieldDarcsPatchFormat}" name="@{fieldDarcsPatchFormat}">
+                    <option value="@DarcsPatchFormat.Default.option">@DarcsPatchFormat.Default</option>
+                    @for(patchFormat <- DarcsPatchFormat.values.filterNot(_ === DarcsPatchFormat.Default)) {
+                      <option value="@patchFormat.option" @if(formData(fieldDarcsPatchFormat).headOption.exists(_ === patchFormat.option)){selected="selected"}else{}>@patchFormat</option>
+                    }
+                  </select>
+                  <span class="pure-form-message" id="@{fieldDarcsPatchFormat}.help">@Messages("form.create-repo.darcs-patch-format.help")</span>
+                  @renderFormErrors(fieldDarcsPatchFormat, formErrors)
+                </div>
                 @csrfToken(csrf)
                 <div class="pure-controls">
                   <button type="submit" class="pure-button">@Messages("form.create-repo.button.submit")</button>