Source

ocaml-bitbucket / api.ml

open Printf
open Common

open Json_conv  (* for conv(json) *)
open Ocaml_conv (* for conv(ocaml) *)

(* field of type Json.t mc_leftovers is automatically handled for Json, but not for ocaml *)
type 'target mc_leftovers = (string * 'target) list with conv(ocaml)

(* CR jfuruse: mc_fields should be supported in Ocaml_conv *)
type 'target mc_fields = (string * 'target) list with conv(ocaml)

(** { 6 Types } *)

module Scheme = struct
  type t = 
    | Hg  (:"hg":) 
    | Git (:"git":) 
  with conv(json), conv(ocaml)
end

module LocalTime = struct
  (* CRv2 jfuruse: this should be lazily parsed date *)
  type t = string with conv(json), conv(ocaml)
end

module UTCTime = struct
  (* CRv2 jfuruse: this should be lazily parsed date *)
  type t = string with conv(json), conv(ocaml)
end

(* CR jfuruse: can be shared with other json apps *)
module Error = struct
  open Format

  let wrap_json_conv convf s = match convf s with
    | `Ok v -> `Ok v
    | `Error e -> `Error (`Json_conv e)

  let format ppf = function
    | `Http (n, _err) -> fprintf ppf "HTTP Error %d@." n
    | `Json_parse exn -> fprintf ppf "Error at Json parse: %s@." (Printexc.to_string exn)
    | `Other exn      -> fprintf ppf "Error: %s@." (Printexc.to_string exn)
    | `Json_conv e    -> Json_conv.format_full_error Format.err_formatter e
end

module Data = struct

  (* CR jfuruse: It seems we should use classes since there are so many name overloads *)
    
  (** Full repository information *)
  module Repository = struct
    type t = <
      name              : string;
      scm               : Scheme.t;
      has_wiki          : bool;
      last_updated      : LocalTime.t;
      utc_last_updated  : UTCTime.t;
      created_on        : LocalTime.t;
      utc_created_on    : UTCTime.t;
      owner             : string;
      logo              : string;
      email_mailinglist : string option;
      is_mq             : bool;
      size              : int;
      read_only         : bool;
      followers_count   : int;
      state             : string; (* "str(available)" *)
      website           : string option;
      description       : string option;
      has_issues        : bool;
      is_fork           : bool;
      slug              : string;
      is_private        : bool;
      language          : string;
      email_writers     : bool;
      no_public_forks   : bool;
      resource_uri      : string;
      fork_of           : t option;
      mq_of             : t option;
      creator           : string option;
    > with conv(json), conv(ocaml)
  end

  (** Commited file *)  
  module File = struct
    type t = <
      type_ as "type" : string;
      file : string;
    > with conv(json), conv(ocaml)
  end

  (** Branch info *)    
  module Branch = struct

    type t = <
      node         : string;
      raw_node     : string;
      author       : string;
      raw_author   : string;
      utctimestamp : UTCTime.t;
      timestamp    : LocalTime.t;
      message      : string;
      files        : File.t list;
      size         : int64;
      revision     : int64;
      parents      : string list;
      branch       : string;
      unknown      : Json.t mc_leftovers;
    > with conv(json), conv(ocaml)

  end

  (** User identity info *)
  module UserID = struct
    type t = <
      username     : string;
      display_name : string;
      first_name   : string;
      last_name    : string;
      is_team      : bool;
      avatar       : string;
      resource_uri : string;
      user_rest    : Json.t mc_leftovers;
    > with conv(json), conv(ocaml)
  end

  module User = struct
    type t = <
      user : UserID.t;
      repositories : Repository.t list;
      rest : Json.t mc_leftovers;
    > with conv(json), conv(ocaml)
  end

  module UserRepo = struct

    (** Small version of Repository.t *)  
    type t = <
      owner      : string;
      scm        : Scheme.t;
      slug       : string;
      is_private : bool;
      name       : string
    >

    and ts = t list with conv(json)
  end

end

(** { 6 End points } *)

(** repositories Endpoint *)
module Repositories = struct

  (* https://api.bitbucket.org/1.0/repositories/{accountname}/{repo_slug}/branches *)
  module Branches = struct

    type t = Data.Branch.t mc_fields with conv(json), conv(ocaml)

    let get ~accountname ~repo_slug = 
      Format.eprintf "%s : %s...@." accountname repo_slug;
      Json.curl_get_and_parse 
        t_of_json
        (fun h ->
          (* ~user ~password  *)
          (* h#set_userpwd (Printf.sprintf "%s:%s" user password)) *)
          h#set_url (sprintf "https://api.bitbucket.org/1.0/repositories/%s/%s/branches" accountname repo_slug)
          (* h#set_userpwd (Printf.sprintf "%s:%s" user password) *) )
  end
end

(** user Endpoint *)
module User = struct

  let get ~user ~password = 
    Json.curl_get_and_parse
      Data.User.t_of_json
      (fun h ->
        h#set_url "https://api.bitbucket.org/1.0/user";
        h#set_userpwd (Printf.sprintf "%s:%s" user password))

  module Repositories = struct

    let get ~user ~password = 
      Json.curl_get_and_parse
        Data.UserRepo.ts_of_json
        (fun h ->
          h#set_url "https://api.bitbucket.org/1.0/user/repositories/";
          h#set_userpwd (Printf.sprintf "%s:%s" user password))
  end

end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.