From 2559ad0cc5e8aba5e82f96fe422b661364a2f726 Mon Sep 17 00:00:00 2001 From: xvw Date: Tue, 30 Jul 2024 19:36:24 +0200 Subject: [PATCH] Start implementing index --- lib/action.ml | 38 ++++++++++++++++++++++++++++++++++++-- lib/chain.ml | 2 ++ lib/chain.mli | 3 +++ lib/dune | 2 +- lib/model.ml | 40 +++++++++++++++++++++++++++++++++------- lib/model.mli | 19 +++++++++++++++++++ lib/resolver.ml | 9 +++++++++ lib/sigs.mli | 43 ++++++++++++------------------------------- 8 files changed, 115 insertions(+), 41 deletions(-) diff --git a/lib/action.ml b/lib/action.ml index 3905b74..daa6538 100644 --- a/lib/action.ml +++ b/lib/action.ml @@ -1,3 +1,18 @@ +let process_css (module R : Sigs.RESOLVER) = + Yocaml.Action.batch ~only:`Files + ~where:(Yocaml.Path.has_extension "css") + R.Source.css + (Yocaml.Action.copy_file ~into:R.Target.css) + +let process_fonts (module R : Sigs.RESOLVER) = + Yocaml.Action.batch ~only:`Files R.Source.fonts + (Yocaml.Action.copy_file ~into:R.Target.fonts) + +let process_images (module R : Sigs.RESOLVER) cache = + cache + |> Yocaml.Action.batch ~only:`Files R.Source.static_images + (Yocaml.Action.copy_file ~into:R.Target.images) + let init_chain (module R : Sigs.RESOLVER) = let open Yocaml.Eff in let* cache = Yocaml.Action.restore_cache ~on:`Target R.Target.cache in @@ -30,7 +45,8 @@ let final_message _cache = Yocaml.Eff.log ~level:`Debug "ring.muhokama done" let generate_opml (module R : Sigs.RESOLVER) chain = Yocaml.Action.write_static_file R.Target.ring_opml (let open Yocaml.Task in - Yocaml.Pipeline.track_files (R.Source.members :: R.Source.common_deps) + R.track_common_dependencies + >>> Yocaml.Pipeline.track_file R.Source.members >>> const chain >>> Chain.to_opml) @@ -43,7 +59,7 @@ let process_chain_member (module R : Sigs.RESOLVER) pred_or_succ current_member in Yocaml.Action.write_static_file target (let open Yocaml.Task in - Yocaml.Pipeline.track_files R.Source.common_deps + R.track_common_dependencies >>> const target_member >>> empty_body () >>> Yocaml_jingoo.Pipeline.as_template @@ -60,13 +76,31 @@ let process_chain (module R : Sigs.RESOLVER) chain = |> process_chain_member `Pred curr pred >>= process_chain_member `Succ curr succ) +let process_index (module R : Sigs.RESOLVER) _chain = + Yocaml.Action.write_static_file R.Target.index + (let open Yocaml.Task in + R.track_common_dependencies + >>> Yocaml.Pipeline.track_file R.Source.members + >>> Yocaml_yaml.Pipeline.read_file_with_metadata + (module Model.Page) + R.Source.index + >>> Yocaml_omd.content_to_html () + >>> Yocaml_jingoo.Pipeline.as_template + (module Model.Page) + (R.Source.template "layout.html") + >>> drop_first ()) + let process_all (module R : Sigs.RESOLVER) () = let open Yocaml.Eff in let* () = init_message (module R) in let* cache, chain = init_chain (module R) in return cache >>= Yocaml.Action.copy_file ~into:R.Target.root R.Source.cname + >>= process_fonts (module R) + >>= process_css (module R) + >>= process_images (module R) >>= generate_opml (module R) chain >>= process_chain (module R) chain + >>= process_index (module R) chain >>= Yocaml.Action.store_cache R.Target.cache >>= final_message diff --git a/lib/chain.ml b/lib/chain.ml index 6b4e366..a26991c 100644 --- a/lib/chain.ml +++ b/lib/chain.ml @@ -8,6 +8,8 @@ type elt = { type t = elt list +let empty = [] + let from_member_list = function | [] -> [] | x :: xs -> diff --git a/lib/chain.mli b/lib/chain.mli index c7d0eeb..eead7dd 100644 --- a/lib/chain.mli +++ b/lib/chain.mli @@ -34,3 +34,6 @@ val to_list : t -> (Model.Member.t * (Model.Member.t * Model.Member.t)) list val to_opml : (t, string) Yocaml.Task.t (** [to_opml] An arrow that lift a chain into an OPML file. *) + +val empty : t +(** [empty] returns an empty chain. *) diff --git a/lib/dune b/lib/dune index 41f62ed..7de2bdd 100644 --- a/lib/dune +++ b/lib/dune @@ -3,4 +3,4 @@ (public_name ring.gem) (synopsis "The name [gem] is because it's set with a ring. lol") (modules_without_implementation sigs) - (libraries yocaml yocaml_yaml yocaml_syndication yocaml_jingoo)) + (libraries yocaml yocaml_yaml yocaml_syndication yocaml_jingoo yocaml_omd)) diff --git a/lib/model.ml b/lib/model.ml index ebbb7a0..d531239 100644 --- a/lib/model.ml +++ b/lib/model.ml @@ -94,14 +94,15 @@ module Link = struct in (title, lang, url)) - let normalize (title, lang, url) = + let normalize_underlying_link (title, lang, url) = let open Yocaml.Data in - record - [ - ("title", string title); - ("lang", Lang.normalize lang); - ("url", Url.normalize url); - ] + [ + ("title", string title); + ("lang", Lang.normalize lang); + ("url", Url.normalize url); + ] + + let normalize link = Yocaml.Data.record (normalize_underlying_link link) let pp ppf (title, lang, url) = Format.fprintf ppf "%s, %a, %a" title Lang.pp lang Url.pp url @@ -270,6 +271,31 @@ module Member = struct main_feed @ additional_feeds end +module Page = struct + type t = { page_title : string option; description : string option } + + let entity_name = "Page" + let empty = { page_title = None; description = None } + let neutral = Ok { page_title = None; description = None } + + let validate_underlying_page fields = + let open Yocaml.Data.Validation in + let+ page_title = optional fields "page_title" string + and+ description = optional fields "description" string in + { page_title; description } + + let validate = Yocaml.Data.Validation.record validate_underlying_page + + let normalize { page_title; description } = + let open Yocaml.Data in + [ + ("has_page_title", has_opt page_title); + ("page_title", option string page_title); + ("has_description", has_opt description); + ("description", option string description); + ] +end + module Chain = struct type t = string list diff --git a/lib/model.mli b/lib/model.mli index e9a0013..75810eb 100644 --- a/lib/model.mli +++ b/lib/model.mli @@ -83,6 +83,8 @@ module Link : sig type t (** The type describing a member. *) + val normalize_underlying_link : t -> (string * Yocaml.Data.t) list + val validate : Yocaml.Data.t -> t Yocaml.Data.Validation.validated_value (** [validate data] validate a link from a {!type:Yocaml.Data.t} value. *) @@ -156,3 +158,20 @@ module Chain : sig include Yocaml.Required.DATA_READABLE with type t := t end + +module Page : sig + (** Describes a generic page, mostly used on top of another model. *) + + type t + (** The type describing a page. *) + + val empty : t + + val validate_underlying_page : + (string * Yocaml.Data.t) list -> t Yocaml.Data.Validation.validated_record + + (** {1 Dealing as metadata} *) + + include Yocaml.Required.DATA_READABLE with type t := t + include Yocaml.Required.DATA_INJECTABLE with type t := t +end diff --git a/lib/resolver.ml b/lib/resolver.ml index 4062a25..c445a94 100644 --- a/lib/resolver.ml +++ b/lib/resolver.ml @@ -8,12 +8,15 @@ module Make (R : Sigs.RESOLVABLE) = struct let data = Path.(R.source / "data") let static = Path.(R.source / "static") let css = Path.(static / "css") + let fonts = Path.(static / "fonts") let templates = Path.(static / "templates") let template file = Path.(templates / file) let members = Path.(data / "members") let chain = Path.(data / "chain.yml") let common_deps = [ binary; chain ] let cname = Path.(static / "CNAME") + let index = Path.(data / "index.md") + let static_images = Path.(static / "images") end module Target = struct @@ -22,6 +25,10 @@ module Make (R : Sigs.RESOLVABLE) = struct let opml = Path.(R.target / "opml") let ring_opml = Path.(opml / "ring.opml") let members = Path.(R.target / "u") + let css = Path.(R.target / "css") + let fonts = Path.(R.target / "fonts") + let index = Path.(R.target / "index.html") + let images = Path.(R.target / "images") let member_redirection ~id pred_or_succ = let target = Path.(members / id) in @@ -29,4 +36,6 @@ module Make (R : Sigs.RESOLVABLE) = struct | `Pred -> Path.(target / "pred" / "index.html") | `Succ -> Path.(target / "succ" / "index.html") end + + let track_common_dependencies = Yocaml.Pipeline.track_files Source.common_deps end diff --git a/lib/sigs.mli b/lib/sigs.mli index 92b004b..caa6e77 100644 --- a/lib/sigs.mli +++ b/lib/sigs.mli @@ -21,6 +21,9 @@ module type RESOLVER = sig include RESOLVABLE (** @inline *) + val track_common_dependencies : (unit, unit) Yocaml.Task.t + (** An arrow that track common dependencies*) + (** {1 Source} Provides utilities for building paths relative to the project source. *) @@ -29,28 +32,17 @@ module type RESOLVER = sig (** Describes the source resolvers. *) val root : Yocaml.Path.t - (** [R.Source.root] is [R.source]. *) - val binary : Yocaml.Path.t - (** Resolve the binary. *) - val cname : Yocaml.Path.t - (** Resolve the CNAME file. *) - val common_deps : Yocaml.Path.t list - (** A list of default dependencies. *) - val data : Yocaml.Path.t - (** Resolve the [data-path] ([source / data]). *) - val static : Yocaml.Path.t - (** Resolve the [static-path] ([source / static]). *) - val css : Yocaml.Path.t - (** Resolve the [css-path] ([source / static / css]). *) - + val fonts : Yocaml.Path.t val templates : Yocaml.Path.t - (** Resolve the [templates-path] ([source / static / templates]). *) + val members : Yocaml.Path.t + val chain : Yocaml.Path.t + val index : Yocaml.Path.t val template : Yocaml.Path.fragment -> Yocaml.Path.t (** [template ?ext file] resolve a template file located into [templates] @@ -59,11 +51,7 @@ module type RESOLVER = sig {b Warning} The function simply produces a path, there is no guarantee that the template exists. *) - val members : Yocaml.Path.t - (** Resolve the members location. *) - - val chain : Yocaml.Path.t - (** Resolve the chain enumeration location. *) + val static_images : Yocaml.Path.t end (** {1 Target} @@ -74,21 +62,14 @@ module type RESOLVER = sig (** Describes the target resolvers. *) val root : Yocaml.Path.t - (** [R.Target.root] is [R.target]. *) - val cache : Yocaml.Path.t - (** Resolve the cache location. *) - + val css : Yocaml.Path.t + val fonts : Yocaml.Path.t val opml : Yocaml.Path.t - (** Resolve the OPML folder location. *) - val ring_opml : Yocaml.Path.t - (** Resolve the OPML file for member's feed. *) - + val index : Yocaml.Path.t + val images : Yocaml.Path.t val members : Yocaml.Path.t - (** Resolve the members directory. *) - val member_redirection : id:string -> [ `Pred | `Succ ] -> Yocaml.Path.t - (** Resolve the link for an user redirection. *) end end