Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support <pkg>.opam files #53

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ _build/src/opam_publish.%: ALWAYS

PREFIX ?= $(shell opam config var prefix)
install:
@opam-installer --prefix=$(PREFIX) opam-publish.install
@opam-installer --prefix=$(PREFIX) publish.install
remove:
@opam-installer -u --prefix=$(PREFIX) opam-publish.install
@opam-installer -u --prefix=$(PREFIX) publish.install

clean:
ocamlbuild -clean
Expand Down
252 changes: 172 additions & 80 deletions src/opam_publish.ml
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,69 @@ let submit ?msg repo_label user_opt package title meta_dir =

(* -- Prepare command -- *)

module Pkg = struct
type filename_form =
| Opam
| Pkg_dot_opam of OpamPackage.Name.t

type t =
{ fname_form : filename_form
; opam_file : OpamFilename.t option
; descr_file : OpamFilename.t option
; files_dir : OpamFilename.Dir.t option
}

let interpret_basename base =
match OpamFilename.Base.to_string base with
| "opam" -> Some Opam
| base when OpamStd.String.ends_with base ~suffix:".opam" ->
Some (Pkg_dot_opam
(OpamStd.String.remove_suffix base ~suffix:".opam"
|> OpamPackage.Name.of_string))
| _ -> None

let scan_dir dir =
let open OpamFilename.Op in
let open OpamStd.Option.Op in (* Option monad *)
let opam_and_pkg_dot_opam_files =
OpamStd.List.filter_map
(fun file ->
interpret_basename (OpamFilename.basename file)
>>| fun fname_form ->
match fname_form with
| Opam ->
{ fname_form
; opam_file = Some file
; descr_file = OpamFilename.opt_file (dir // "descr")
; files_dir = OpamFilename.opt_dir (dir / "files")
}
| Pkg_dot_opam _ ->
{ fname_form
; opam_file = Some file
; descr_file = None
; files_dir = None
})
(OpamFilename.files dir)
in
let opam_and_pkg_dot_opam_dirs =
OpamStd.List.filter_map
(fun dir ->
interpret_basename (OpamFilename.basename_dir dir)
>>| fun fname_form ->
{ fname_form
; opam_file = OpamFilename.opt_file (dir // "opam" )
; descr_file = OpamFilename.opt_file (dir // "descr")
; files_dir = OpamFilename.opt_dir (dir / "files")
})
(OpamFilename.dirs dir)
in
opam_and_pkg_dot_opam_files @ opam_and_pkg_dot_opam_dirs
end

let prepare ?name ?version ?(repo_label=default_label) http_url =
let open OpamFilename.Op in
let open OpamStd.Option.Op in (* Option monad *)
let open Pkg in
OpamFilename.with_tmp_dir @@ fun tmpdir ->
(* Fetch the archive *)
let url = OpamUrl.parse ~handle_suffix:true http_url in
Expand All @@ -636,90 +696,93 @@ let prepare ?name ?version ?(repo_label=default_label) http_url =
(* Utility functions *)
let f_opt f = if OpamFilename.exists f then Some f else None in
let dir_opt d = if OpamFilename.exists_dir d then Some d else None in
let get_file name reader dir =
dir >>= dir_opt >>= fun d ->
f_opt (d // name) >>= fun f ->
let read_file reader f =
try Some (f, reader (OpamFile.make f))
with OpamPp.Bad_format _ -> None
in
let get_opam = get_file "opam" OpamFile.OPAM.read in
let get_descr dir =
get_file "descr" OpamFile.Descr.read dir >>= fun (_,d as descr) ->
if OpamFile.Descr.synopsis d = OpamFile.Descr.synopsis descr_template
then None else Some descr
in
let get_files_dir dir = dir >>= dir_opt >>= fun d -> dir_opt (d / "files") in
(* Get opam from the archive *)
let src_meta_dir = dir_opt (srcdir / "opam") ++ dir_opt srcdir in
let src_opam = get_opam src_meta_dir in
(* Guess package name and version *)
let name = match name, src_opam >>| snd >>= OpamFile.OPAM.name_opt with
| None, None ->
OpamConsole.error_and_exit "Package name unspecified"
| Some n1, Some n2 when n1 <> n2 ->
OpamConsole.warning
"Publishing as package %s, while it refers to itself as %s"
(OpamPackage.Name.to_string n1) (OpamPackage.Name.to_string n2);
n1
| Some n, _ | None, Some n -> n
in
let version =
match version ++ (src_opam >>| snd >>= OpamFile.OPAM.version_opt) with
| None ->
OpamConsole.error_and_exit "Package version unspecified"
| Some v -> v
in
let package = OpamPackage.create name version in
(* Metadata sources: from OPAM overlay, prepare dir, git mirror, archive.
Could add: from highest existing version on the repo ? Better
advise pinning at the moment to encourage some testing. *)
let prepare_dir_name = OpamFilename.cwd () / OpamPackage.to_string package in
let prepare_dir = dir_opt prepare_dir_name in
let overlay_dir =
if has_dotopam <> None then
OpamStateConfig.(!r.current_switch) >>| fun switch ->
OpamPath.Switch.Overlay.package opam_root switch name
else
None
in
let repo = dir_opt (repo_dir repo_label) >>| repo_of_dir in
(repo >>| update_mirror) +! ();
let has_pr = (repo >>| reset_to_existing_pr package) +! false in
let pub_dir = repo >>= get_git_user_dir package in
let other_versions_pub_dir =
if has_pr then None else repo >>= get_git_max_v_dir package
in
(* Choose metadata from the sources *)
let prep_url =
(* Todo: advise mirrors if existing in other versions ? *)
OpamFile.URL.with_checksum [checksum] (OpamFile.URL.create url)
let get_file name dir =
dir >>= dir_opt >>= fun d ->
f_opt (d // name)
in
let chosen_opam_and_files =
let get_opam_and_files dir =
get_opam dir >>| fun o -> o, get_files_dir dir
let prepare_one version (pkg : Pkg.t) =
let get_opam dir = get_file "opam" dir >>= read_file OpamFile.OPAM.read in
let read_descr f =
read_file OpamFile.Descr.read f >>= fun (_,d as descr) ->
if OpamFile.Descr.synopsis d = OpamFile.Descr.synopsis descr_template
then None else Some descr
in
get_opam_and_files overlay_dir ++
get_opam_and_files prepare_dir ++
get_opam_and_files pub_dir ++
get_opam_and_files src_meta_dir
in
let chosen_descr =
get_descr overlay_dir ++
get_descr prepare_dir ++
get_descr pub_dir ++
get_descr src_meta_dir ++
get_descr other_versions_pub_dir
in
(* Choose and copy or write *)
OpamFilename.mkdir prepare_dir_name;
let prepare_dir = prepare_dir_name in
match chosen_opam_and_files with
| None ->
OpamConsole.error_and_exit
"No metadata found. \
Try pinning the package locally (`opam pin add %s %S`) beforehand."
(OpamPackage.Name.to_string name) http_url
| Some ((opam_file, opam), files_opt) ->
let get_descr dir = get_file "descr" dir >>= read_descr in
let get_files_dir dir = dir >>= dir_opt >>= fun d -> dir_opt (d / "files") in
(* Get opam from the archive *)
let src_opam = pkg.opam_file >>= read_file OpamFile.OPAM.read in
(* Guess package name and version *)
let name = match pkg.fname_form, src_opam >>| snd >>= OpamFile.OPAM.name_opt with
| Opam, None ->
OpamConsole.error_and_exit "Package name unspecified"
| Pkg_dot_opam n1, Some n2 when n1 <> n2 ->
OpamConsole.warning
"Publishing as package %s, while it refers to itself as %s"
(OpamPackage.Name.to_string n1) (OpamPackage.Name.to_string n2);
n1
| Pkg_dot_opam n, _ | Opam, Some n -> n
in
let version =
match version ++ (src_opam >>| snd >>= OpamFile.OPAM.version_opt) with
| None ->
OpamConsole.error_and_exit "Package version unspecified"
| Some v -> v
in
let package = OpamPackage.create name version in
(* Metadata sources: from OPAM overlay, prepare dir, git mirror, archive.
Could add: from highest existing version on the repo ? Better
advise pinning at the moment to encourage some testing. *)
let prepare_dir_name = OpamFilename.cwd () / OpamPackage.to_string package in
let prepare_dir = dir_opt prepare_dir_name in
let overlay_dir =
if has_dotopam <> None then
OpamStateConfig.(!r.current_switch) >>| fun switch ->
OpamPath.Switch.Overlay.package opam_root switch name
else
None
in
let repo = dir_opt (repo_dir repo_label) >>| repo_of_dir in
(repo >>| update_mirror) +! ();
let has_pr = (repo >>| reset_to_existing_pr package) +! false in
let pub_dir = repo >>= get_git_user_dir package in
let other_versions_pub_dir =
if has_pr then None else repo >>= get_git_max_v_dir package
in
(* Choose metadata from the sources *)
let prep_url =
(* Todo: advise mirrors if existing in other versions ? *)
OpamFile.URL.with_checksum [checksum] (OpamFile.URL.create url)
in
let chosen_opam_and_files =
let get_opam_and_files dir =
get_opam dir >>| fun o -> o, get_files_dir dir
in
get_opam_and_files overlay_dir ++
get_opam_and_files prepare_dir ++
get_opam_and_files pub_dir ++
(src_opam >>| fun o -> (o, pkg.files_dir))
in
let chosen_descr =
get_descr overlay_dir ++
get_descr prepare_dir ++
get_descr pub_dir ++
(pkg.descr_file >>= read_descr) ++
get_descr other_versions_pub_dir
in
(* Choose and copy or write *)
OpamFilename.mkdir prepare_dir_name;
let prepare_dir = prepare_dir_name in
match chosen_opam_and_files with
| None ->
OpamConsole.error_and_exit
"No metadata found. \
Try pinning the package locally (`opam pin add %s %S`) beforehand."
(OpamPackage.Name.to_string name) http_url
| Some ((opam_file, opam), files_opt) ->
let open OpamFile in
let opam =
opam |>
Expand Down Expand Up @@ -754,7 +817,36 @@ let prepare ?name ?version ?(repo_label=default_label) http_url =
\ * Run 'opam publish submit ./%s' to submit your package\n"
(OpamPackage.to_string package)
(OpamPackage.to_string package)

in
let pkgs = Pkg.scan_dir srcdir in
match List.find (fun pkg -> pkg.fname_form = Opam) pkgs with
| pkg ->
(* If there is an "opam" file or directory, ignore "<pkg>.opam" files or
directories *)
prepare_one version pkg
| exception Not_found ->
match name with
| None ->
List.iter (prepare_one version) pkgs
| Some name ->
match List.find (fun pkg -> pkg.fname_form = Pkg_dot_opam name) pkgs with
| pkg ->
prepare_one version pkg
| exception Not_found ->
match pkgs with
| [] ->
(* Same as old behavior *)
prepare_one version
{ fname_form = Pkg_dot_opam name
; opam_file = None
; descr_file = f_opt (srcdir // "descr")
; files_dir = dir_opt (srcdir / "files")
}
| _ ->
OpamConsole.error_and_exit
"There are <pkg>.opam files/directories but no %s.opam. \
I can't decide which opam file to use."
(OpamPackage.Name.to_string name)

(* -- Command-line handling -- *)

Expand Down