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

next: add package subcommand #2551

Closed
wants to merge 8 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Makefile
Expand Up @@ -226,6 +226,7 @@ SRC_client = \
opamPinCommand.ml \
opamListCommand.ml \
opamClient.ml \
opamPackageCommand.ml \
opamGitVersion.ml \
opamArg.ml

Expand Down
36 changes: 36 additions & 0 deletions src/client/opamMain.ml
Expand Up @@ -1295,6 +1295,41 @@ let pin ?(unpin_only=false) () =
$command $params),
term_info "pin" ~doc ~man

(* PACKAGE *)
let package_doc = "XXX: Maintainers, fill this in"
let package =
let doc = package_doc in
let commands =
[ "build", `build, [], "XXX: Maintainers, fill this in";
"test", `test, [], "XXX: Maintainers, fill this in";
"doc", `doc, [], "XXX: Maintainers, fill this in" ]
in
let man = [
`S "DESCRIPTION";
`P "XXX: Maintainers, fill this in."
] in
let command, params = mk_subcommands commands in
let package global_options command params =
apply_global_options global_options;
let path = OpamFilename.raw_dir "." in
match command, params with
| Some `build, [] ->
OpamGlobalState.with_ `Lock_none @@ fun gt ->
OpamSwitchState.with_ `Lock_write gt @@ fun st ->
`Ok (OpamPackageCommand.build st path)
| Some `test , [] ->
OpamGlobalState.with_ `Lock_none @@ fun gt ->
OpamSwitchState.with_ `Lock_write gt @@ fun st ->
`Ok (OpamPackageCommand.build st ~build_test:true path)
| Some `doc , [] ->
OpamGlobalState.with_ `Lock_none @@ fun gt ->
OpamSwitchState.with_ `Lock_write gt @@ fun st ->
`Ok (OpamPackageCommand.build st ~build_doc:true path)
| _ , _ -> bad_subcommand commands ("package", command, params)
in
Term.(ret (pure package $ global_options $ command $ params)),
term_info "package" ~doc ~man

(* SOURCE *)
let source_doc = "Get the source of an OPAM package."
let source =
Expand Down Expand Up @@ -1576,6 +1611,7 @@ let commands = [
repository; make_command_alias repository "remote";
switch;
pin (); make_command_alias (pin ~unpin_only:true ()) ~options:" remove" "unpin";
package;
source;
lint;
help;
Expand Down
57 changes: 57 additions & 0 deletions src/client/opamPackageCommand.ml
@@ -0,0 +1,57 @@
(*----------------------------------------------------------------------------
Copyright (c) 2016 Inhabited Type LLC <spiros@inhabitedtype.com>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Neither the name of the author nor the names of his contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------*)

let default_nv =
match OpamPackage.of_string_opt "local-package.dev" with
| Some nv -> nv
| None -> assert false

let build t ?build_test ?build_doc dir =
let name = OpamPackage.name default_nv in
let pred dir = None <> OpamPinned.find_opam_file_in_source name dir in
let dir =
match OpamFilename.find_ancestor_dir pred dir with
| Some dir -> dir
| None ->
OpamConsole.error "No valid package description found.";
OpamStd.Sys.exit 1
in
(* XXX(seliopou): This whole dance is necessary because
* OpamAction.build_package reads global state, rather than explicitly taking
* the build_test and build_doc arguments *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. It would be best to add them as arguments troughout. Meanwhile, it may be more consistent to remove the argument here and relying on the options being set in OpamMain.

Note that since we would like to be able to set these options for specific packages (#2506), this will need to be changed anyway at that point.

let old_r = OpamStateConfig.(!r) in
try
OpamStateConfig.update ?build_test ?build_doc ();
OpamAction.build_package t (`In_place dir) default_nv;
OpamStateConfig.r := old_r
with exn -> OpamStateConfig.r := old_r; raise exn
38 changes: 38 additions & 0 deletions src/client/opamPackageCommand.mli
@@ -0,0 +1,38 @@
(*----------------------------------------------------------------------------
Copyright (c) 2016 Inhabited Type LLC <spiros@inhabitedtype.com>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Neither the name of the author nor the names of his contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------*)

open OpamTypes
open OpamStateTypes

val build :
rw switch_state -> ?build_test:bool -> ?build_doc:bool -> dirname -> unit
11 changes: 11 additions & 0 deletions src/core/opamFilename.ml
Expand Up @@ -123,6 +123,17 @@ let basename_dir dirname =
let dirname_dir dirname =
Dir.to_string (Filename.dirname (Dir.of_string dirname))

let find_ancestor_dir pred dir =
let root = raw_dir "/" in
let rec loop dir =
if pred dir then Some dir
else if dir = root then None
else loop (dirname_dir dir)
in
if not (exists_dir dir)
then None
else loop dir

let to_list_dir dir =
let base d = Dir.of_string (Filename.basename (Dir.to_string d)) in
let rec aux acc dir =
Expand Down
3 changes: 3 additions & 0 deletions src/core/opamFilename.mli
Expand Up @@ -77,6 +77,9 @@ val dirname_dir: Dir.t -> Dir.t
(** Return the deeper directory name *)
val basename_dir: Dir.t -> Base.t

(** Find an ancestor of the directory that satisfies the predicate. *)
val find_ancestor_dir : (Dir.t -> bool) -> Dir.t -> Dir.t option

(** Turn a full path into a list of directory names *)
val to_list_dir: Dir.t -> Dir.t list

Expand Down
17 changes: 13 additions & 4 deletions src/state/opamAction.ml
Expand Up @@ -512,9 +512,19 @@ let remove_package t ?keep_build ?silent nv =
(* Compiles a package.
Assumes the package has already been downloaded to [source].
*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have written one core function and two exported functions for the two modes, rather than a mode argument; but it's just a a matter of taste, this is fine.

let build_package t source nv =
extract_package t source nv;
let opam = OpamSwitchState.opam t nv in
let build_package t mode nv =
let dir, opam =
match mode with
| `Extract source ->
extract_package t source nv;
OpamPath.Switch.build t.switch_global.root t.switch nv,
OpamSwitchState.opam t nv
| `In_place dir ->
let name = OpamPackage.name nv in
match OpamPinned.find_opam_file_in_source name dir with
| None -> raise Not_found
| Some file -> dir, OpamFile.OPAM.read file
in
let commands =
OpamFile.OPAM.build opam @
(if OpamStateConfig.(!r.build_test)
Expand All @@ -527,7 +537,6 @@ let build_package t source nv =
in
let env = OpamTypesBase.env_array (compilation_env t opam) in
let name = OpamPackage.name_to_string nv in
let dir = OpamPath.Switch.build t.switch_global.root t.switch nv in
let rec run_commands = function
| (cmd::args)::commands ->
let text = OpamProcess.make_command_text name ~args cmd in
Expand Down
14 changes: 10 additions & 4 deletions src/state/opamAction.mli
Expand Up @@ -31,11 +31,17 @@ val download_package:
val extract_package:
rw switch_state -> generic_file option -> package -> unit

(** [build_package t source pkg] builds the package [pkg] from its
already downloaded [source]. Returns [None] on success, [Some exn]
on error. See {!download_package} to download the source. *)
(** [build_package t mode pkg] builds the package [pkg]. If
[mode = `Extract generic_file] then the package will be built from its
already extracted source. If [mode = `In_place dirname] then the package
will be built in-place, indepedent of switch metadata.

Returns [None] on success, [Some exn] on error. See {!download_package} to
download the source. *)
val build_package:
rw switch_state -> generic_file option -> package ->
rw switch_state ->
[`Extract of generic_file option | `In_place of dirname] ->
package ->
exn option OpamProcess.job

(** [install_package t pkg] installs an already built package. Returns
Expand Down
2 changes: 1 addition & 1 deletion src/state/opamSolution.ml
Expand Up @@ -433,7 +433,7 @@ let parallel_apply t action action_graph =
else
match action with
| `Build nv ->
(OpamAction.build_package t source nv @@+ function
(OpamAction.build_package t (`Extract source) nv @@+ function
| None -> store_time (); Done (`Successful (installed, removed))
| Some exn -> store_time (); Done (`Exception exn))
| `Install nv ->
Expand Down