Browse Source

first commit

main
zapashcanon 1 year ago
commit
deaccd4148
Signed by: zapashcanon GPG Key ID: 8981C3C62D1D28F1
  1. 2
      .gitignore
  2. 42
      .ocamlformat
  3. 1
      CHANGES.md
  4. 8
      LICENSE.md
  5. 40
      README.md
  6. 33
      dune-project
  7. 31
      refdepcounting.opam
  8. 4
      src/dune
  9. 109
      src/refdepcounting.ml

2
.gitignore

@ -0,0 +1,2 @@
_build
.refdepcountingcache

42
.ocamlformat

@ -0,0 +1,42 @@
version=0.24.1
assignment-operator=end-line
break-cases=fit
break-fun-decl=wrap
break-fun-sig=wrap
break-infix=wrap
break-infix-before-func=false
break-separators=before
break-sequences=true
cases-exp-indent=2
cases-matching-exp-indent=normal
doc-comments=before
doc-comments-padding=2
doc-comments-tag-only=default
dock-collection-brackets=false
exp-grouping=preserve
field-space=loose
if-then-else=compact
indicate-multiline-delimiters=space
indicate-nested-or-patterns=unsafe-no
infix-precedence=indent
leading-nested-match-parens=false
let-and=sparse
let-binding-spacing=compact
let-module=compact
margin=80
max-indent=68
module-item-spacing=sparse
ocp-indent-compat=false
parens-ite=false
parens-tuple=always
parse-docstrings=true
sequence-blank-line=preserve-one
sequence-style=terminator
single-case=compact
space-around-arrays=true
space-around-lists=true
space-around-records=true
space-around-variants=true
type-decl=sparse
wrap-comments=false
wrap-fun-args=true

1
CHANGES.md

@ -0,0 +1 @@
## unreleased

8
LICENSE.md

@ -0,0 +1,8 @@
The ISC License (ISC)
=====================
Copyright © 2023, Léo Andrès <contact@ndrs.fr>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

40
README.md

@ -0,0 +1,40 @@
# refdepcounting
[refdepcounting] is an [OCaml] executable/library to TODO.
## Installation
`refdepcounting` can be installed with [opam]:
```sh
opam install refdepcounting
```
If you don't have `opam`, you can install it following the [how to install opam] guide.
If you can't or don't want to use `opam`, consult the [opam file] for build instructions.
## Quickstart
```ocaml
let () = Format.printf "TODO@."
```
For more, have a look at the [example] folder, at the [documentation] or at the [test suite].
## About
- [LICENSE]
- [CHANGELOG]
[CHANGELOG]: ./CHANGES.md
[example]: ./example
[LICENSE]: ./LICENSE.md
[opam file]: ./refdepcounting.opam
[test suite]: ./test
[documentation]: https://doc.zapashcanon.fr/refdepcounting
[how to install opam]: https://opam.ocaml.org/doc/Install.html
[OCaml]: https://ocaml.org
[opam]: https://opam.ocaml.org/
[refdepcounting]: https://git.zapashcanon.fr/zapashcanon/refdepcounting

33
dune-project

@ -0,0 +1,33 @@
(lang dune 3.0)
(implicit_transitive_deps false)
(name refdepcounting)
(license ISC)
(authors "Léo Andrès <contact@ndrs.fr>")
(maintainers "Léo Andrès <contact@ndrs.fr>")
(source
(uri git+https://git.zapashcanon.fr/zapashcanon/refdepcounting.git))
(homepage https://git.zapashcanon.fr/zapashcanon/refdepcounting)
(bug_reports https://git.zapashcanon.fr/zapashcanon/refdepcounting/issues)
(documentation https://doc.zapashcanon.fr/refdepcounting)
(generate_opam_files true)
(package
(name refdepcounting)
(synopsis "OCaml library/executable to TODO")
(description
"refdepcounting is an OCaml library/executable to TODO.")
(tags
(refdepcounting TODO TODO TODO TODO))
(depends
(ocaml
(>= 4.08))))

31
refdepcounting.opam

@ -0,0 +1,31 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
synopsis: "OCaml library/executable to TODO"
description: "refdepcounting is an OCaml library/executable to TODO."
maintainer: ["Léo Andrès <contact@ndrs.fr>"]
authors: ["Léo Andrès <contact@ndrs.fr>"]
license: "ISC"
tags: ["refdepcounting" "TODO" "TODO" "TODO" "TODO"]
homepage: "https://git.zapashcanon.fr/zapashcanon/refdepcounting"
doc: "https://doc.zapashcanon.fr/refdepcounting"
bug-reports: "https://git.zapashcanon.fr/zapashcanon/refdepcounting/issues"
depends: [
"dune" {>= "3.0"}
"ocaml" {>= "4.08"}
"odoc" {with-doc}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://git.zapashcanon.fr/zapashcanon/refdepcounting.git"

4
src/dune

@ -0,0 +1,4 @@
(executable
(name refdepcounting)
(modules refdepcounting)
(libraries unix))

109
src/refdepcounting.ml

@ -0,0 +1,109 @@
let all_packages =
Format.eprintf "listing all packages...@.";
let cmd = "opam list --short --all --color=never" in
let chan = Unix.open_process_in cmd in
let packages = ref [] in
let () =
try
while true do
packages := input_line chan :: !packages
done
with End_of_file -> close_in chan
in
!packages
let deps package =
Format.eprintf " getting dependencies of %s@." package;
let cmd =
Format.sprintf "opam show --color=never --no-lint --field depends %s"
package
in
let chan = Unix.open_process_in cmd in
let deps = ref [] in
begin
try
while true do
let line = input_line chan in
match String.split_on_char ' ' line with
| [] -> ()
| dep :: _stuff ->
if String.length dep > 2 then begin
let dep = String.sub dep 1 (String.length dep - 2) in
deps := dep :: !deps
end
done
with End_of_file -> close_in chan
end;
!deps
let rev_deps =
let cache_file = ".refdepcountingcache" in
if Sys.file_exists ".refdepcountingcache" then begin
Format.eprintf "loading reverse dependencies from cache...@.";
let chan = open_in_bin cache_file in
let tbl = Marshal.from_channel chan in
close_in chan;
tbl
end
else begin
Format.eprintf "building reverse dependencies table...@.";
let tbl = Hashtbl.create (List.length all_packages) in
List.iteri
(fun i package ->
if i mod 50 = 0 || i = List.length all_packages - 1 then begin
Format.eprintf "writing reverse dependencies to cache...@.";
let chan = open_out cache_file in
Marshal.to_channel chan tbl [];
close_out chan
end;
let deps = deps package in
List.iter (fun dep -> Hashtbl.add tbl dep package) deps )
all_packages;
tbl
end
let get_rev_deps package =
List.sort_uniq compare @@ Hashtbl.find_all rev_deps package
let count_rev_deps package =
let rev_deps = get_rev_deps package in
List.length rev_deps
let get_rev_deps_transitive package =
let seen = Hashtbl.create (List.length all_packages) in
let rec aux package =
if Hashtbl.mem seen package then ()
else begin
Hashtbl.replace seen package ();
let deps = Hashtbl.find_all rev_deps package in
List.iter aux deps
end
in
aux package;
Hashtbl.to_seq_keys seen |> List.of_seq
|> List.filter (fun p -> not @@ String.equal p package)
let count_rev_deps_transitive package =
let rev_deps = get_rev_deps_transitive package in
List.length rev_deps
let print_package_with_rdc fmt (count_transitive, count, package) =
Format.fprintf fmt "%s: %d, %d" package count_transitive count
let print_packages_with_rdc fmt packages_with_rdc =
Format.pp_print_list
~pp_sep:(fun fmt () -> Format.fprintf fmt "@.")
print_package_with_rdc fmt packages_with_rdc
let packages_with_rdc =
Format.eprintf "counting reverse dependencies for all packages...@.";
List.rev_map
(fun package ->
(count_rev_deps_transitive package, count_rev_deps package, package) )
all_packages
let sorted_packages =
Format.eprintf "sorting packages by reverse dependencies count...@.";
List.sort compare packages_with_rdc
let () = Format.printf "%a@." print_packages_with_rdc sorted_packages
Loading…
Cancel
Save