fhir_packages_manager 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c2287ea505915de0f129d5ce615c60d6df687ed7253f62a0f3ef0b7f71c4a73
4
- data.tar.gz: 1addb4d25614ee56ee29cbc4ebfe0598cfd2337e8cacde5ca011fcc121110b9f
3
+ metadata.gz: 7d65db7b1f5b29ac8f0064d0cfd224529dc336b2b88c7a4de952206fe81477f7
4
+ data.tar.gz: c16f3255dce19c1058b3781b5695e0c059e6d76b45dc63ff1c35a94891eacaa3
5
5
  SHA512:
6
- metadata.gz: 968af44ee62704494e47c21423c90b067c6ad0265aa4a27c254dcbd005800cc0c1e74ed691cedeefc15289e2b4c77c7012d88626ff0475148c4bfa272d0d7908
7
- data.tar.gz: b1b2b5db5cf50a8a1d63cfc728ba3f0a0d69f37b3037f74d52b208c8620618276090f9c219229f8683f80988c6843044ecfb99f5fa03891ae1a7c0956167d2a3
6
+ metadata.gz: 016d41a5b7f0aed1ce89fa445e149ea85b4e991c9c61d9ba111fab699b113e88b8e62c650f8b08314e5246ca875927dbe0abb9bbdd92b9d68dbf8306c502f68c
7
+ data.tar.gz: bed4d3fb7c4f7abb708837a2ebbd7ecac247c18284b16e51967b216240f98878090df35765dcfdfdf3c8700c41ab785176d05d58747dff6a076ee636ef1ff29a
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2026-07-10
11
+
12
+ ### Added
13
+
14
+ - `sync` CLI command and `Manager#sync`: downloads every non-ignored version of a package not
15
+ already present in the destination folder (checked as `name-version.tgz`, the same naming
16
+ `fetch` uses), reusing `#fetch` for the actual download of each missing version. Output reuses
17
+ `fetch`'s `OK`/`SKIP`/`MISS`/`ERR` lines, with `SKIP` covering both an ignored version and one
18
+ already on disk. (#3)
19
+
10
20
  ## [0.2.0] - 2026-07-10
11
21
 
12
22
  ### Added
@@ -50,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
50
60
  - **Documentation**: YARD doc comments across the public API, and a Codecov/docs badge pair
51
61
  in the README.
52
62
 
53
- [Unreleased]: https://github.com/projkov/fhir_packages_manager/compare/v0.2.0...HEAD
63
+ [Unreleased]: https://github.com/projkov/fhir_packages_manager/compare/v0.3.0...HEAD
64
+ [0.3.0]: https://github.com/projkov/fhir_packages_manager/compare/v0.2.0...v0.3.0
54
65
  [0.2.0]: https://github.com/projkov/fhir_packages_manager/compare/v0.1.0...v0.2.0
55
66
  [0.1.0]: https://github.com/projkov/fhir_packages_manager/releases/tag/v0.1.0
data/README.md CHANGED
@@ -46,6 +46,8 @@ result.path # => "./fhir_packages/hl7.fhir.us.core-6.1.0.tgz" when downloaded
46
46
  manager.fetch_all(["hl7.fhir.us.core@6.1.0", "hl7.fhir.r4.core"]) # bare name = latest
47
47
 
48
48
  manager.list_versions("hl7.fhir.us.core") # => {"https://packages.fhir.org" => ["1.0.0", "1.0.1", ...], ...}
49
+
50
+ manager.sync("hl7.fhir.us.core") # fetches every non-ignored version not already in destination
49
51
  ```
50
52
 
51
53
  The ignore list file (YAML or JSON) is a flat array where a bare string
@@ -66,8 +68,16 @@ exe/fhir_packages_manager fetch hl7.fhir.us.core@6.1.0 hl7.fhir.r4.core \
66
68
  -d ./fhir_packages -i fhir_packages_ignore.yml
67
69
  exe/fhir_packages_manager list hl7.fhir.us.core \
68
70
  -r https://packages.fhir.org -r https://packages.simplifier.net
71
+ exe/fhir_packages_manager sync hl7.fhir.us.core \
72
+ -r https://packages.fhir.org -d ./fhir_packages -i fhir_packages_ignore.yml
69
73
  ```
70
74
 
75
+ `sync` downloads every non-ignored version of a package that isn't already in the destination
76
+ folder (checked as `name-version.tgz`, the same naming `fetch` uses — keep that naming if you
77
+ move the files afterward, since a bare `version.tgz` can collide between two IGs that happen to
78
+ publish the same version number). Its output reuses `fetch`'s `OK`/`SKIP`/`MISS`/`ERR` lines,
79
+ with `SKIP` covering both an ignored version and one already on disk.
80
+
71
81
  ### Docker
72
82
 
73
83
  The CLI is also published as a container image, so it can be used without installing Ruby
@@ -7,7 +7,7 @@ module FhirPackagesManager
7
7
  # See the "CLI" section of the README for usage examples.
8
8
  class CLI
9
9
  # @return [Array<String>] the supported subcommands
10
- COMMANDS = %w[fetch check list].freeze
10
+ COMMANDS = %w[fetch check list sync].freeze
11
11
 
12
12
  # @return [String] usage text shown on --help and on invalid invocations
13
13
  BANNER = <<~USAGE
@@ -17,6 +17,7 @@ module FhirPackagesManager
17
17
  fetch Download packages into the destination folder
18
18
  check Report which registry (if any) has each package/version
19
19
  list List every version of a package available across registries
20
+ sync Download every non-ignored version not already in the destination folder
20
21
 
21
22
  USAGE
22
23
 
@@ -56,6 +57,8 @@ module FhirPackagesManager
56
57
  check(package_specs)
57
58
  when 'list'
58
59
  list(package_specs)
60
+ when 'sync'
61
+ sync(package_specs)
59
62
  end
60
63
  end
61
64
 
@@ -113,9 +116,11 @@ module FhirPackagesManager
113
116
 
114
117
  def fetch_line(result)
115
118
  package = result.package
119
+ path = result.path
116
120
  case result.status
117
- when :downloaded then "OK #{package} -> #{result.path} (#{result.registry})"
121
+ when :downloaded then "OK #{package} -> #{path} (#{result.registry})"
118
122
  when :ignored then "SKIP #{package} (ignored)"
123
+ when :skipped then "SKIP #{package} (already exists at #{path})"
119
124
  when :not_found then "MISS #{package} (not found in any registry)"
120
125
  when :error then "ERR #{package}: #{result.error}"
121
126
  end
@@ -150,5 +155,11 @@ module FhirPackagesManager
150
155
  "FOUND #{name} @ #{base_url}: #{versions.sort.join(', ')}"
151
156
  end
152
157
  end
158
+
159
+ def sync(package_specs)
160
+ results = package_specs.flat_map { |spec| manager.sync(Package.parse(spec).name) }
161
+ results.each { |result| puts fetch_line(result) }
162
+ exit 1 if results.any? { |result| result.not_found? || result.error? }
163
+ end
153
164
  end
154
165
  end
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FhirPackagesManager
4
- # Outcome of {Manager#fetch} for a single package.
4
+ # Outcome of {Manager#fetch} (or {Manager#sync}) for a single package/version.
5
5
  #
6
6
  # @!attribute package
7
7
  # @return [Package] the package that was requested (version resolved, when downloaded)
8
8
  # @!attribute status
9
- # @return [Symbol] one of :downloaded, :ignored, :not_found, :error
9
+ # @return [Symbol] one of :downloaded, :ignored, :skipped, :not_found, :error
10
10
  # @!attribute registry
11
11
  # @return [String, nil] the base URL of the registry that served the package, if downloaded
12
12
  # @!attribute path
13
- # @return [String, nil] where the tarball was written, if downloaded
13
+ # @return [String, nil] where the tarball was (or already is) on disk, if downloaded/skipped
14
14
  # @!attribute error
15
15
  # @return [String, nil] the error message, when status is :error
16
16
  class FetchResult < Struct.new(:package, :status, :registry, :path, :error, keyword_init: true)
@@ -24,6 +24,11 @@ module FhirPackagesManager
24
24
  status == :ignored
25
25
  end
26
26
 
27
+ # @return [Boolean] true if {Manager#sync} skipped it because it was already downloaded
28
+ def skipped?
29
+ status == :skipped
30
+ end
31
+
27
32
  # @return [Boolean] true if no registry had the package/version
28
33
  def not_found?
29
34
  status == :not_found
@@ -80,6 +80,20 @@ module FhirPackagesManager
80
80
  end
81
81
  end
82
82
 
83
+ # Downloads every non-ignored version of a package that isn't already present in
84
+ # {#destination} (as `name-version.tgz`, the same convention {#fetch} downloads use).
85
+ # A whole-package ignore skips it entirely, without querying any registry; an individual
86
+ # ignored version instead surfaces as a normal `:ignored` {FetchResult}, same as {#fetch}.
87
+ #
88
+ # @param name [String] the package name
89
+ # @return [Array<FetchResult>] one result per version considered, across all registries
90
+ def sync(name)
91
+ whole_package = Package.new(name, nil)
92
+ return [FetchResult.new(package: whole_package, status: :ignored)] if ignored?(whole_package)
93
+
94
+ candidate_versions(name).map { |version| sync_version(Package.new(name, version)) }
95
+ end
96
+
83
97
  private
84
98
 
85
99
  def fetch_package(package)
@@ -98,18 +112,37 @@ module FhirPackagesManager
98
112
  end
99
113
 
100
114
  def available_versions(registry, name)
101
- registry.versions(name).reject { |version| ignored?(Package.new(name, version)) }
115
+ raw_versions(registry, name).reject { |version| ignored?(Package.new(name, version)) }
116
+ end
117
+
118
+ def raw_versions(registry, name)
119
+ registry.versions(name)
102
120
  rescue PackageNotFoundError
103
121
  []
104
122
  end
105
123
 
124
+ def candidate_versions(name)
125
+ registries.flat_map { |registry| raw_versions(registry, name) }.uniq
126
+ end
127
+
128
+ def sync_version(package)
129
+ existing_path = download_path(package)
130
+ return FetchResult.new(package: package, status: :skipped, path: existing_path) if File.exist?(existing_path)
131
+
132
+ fetch(package)
133
+ end
134
+
135
+ def download_path(package)
136
+ File.join(destination, "#{package.name}-#{package.version}.tgz")
137
+ end
138
+
106
139
  def download_result(package, found)
107
140
  registry, resolved_version = found
108
141
  name = package.name
109
- target = File.join(destination, "#{name}-#{resolved_version}.tgz")
142
+ resolved_package = Package.new(name, resolved_version)
143
+ target = download_path(resolved_package)
110
144
  registry.download(name, resolved_version, target)
111
- FetchResult.new(package: Package.new(name, resolved_version), status: :downloaded,
112
- registry: registry.base_url, path: target)
145
+ FetchResult.new(package: resolved_package, status: :downloaded, registry: registry.base_url, path: target)
113
146
  end
114
147
  end
115
148
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FhirPackagesManager
4
4
  # @return [String] the gem's version, following semver
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
@@ -34,5 +34,7 @@ module FhirPackagesManager
34
34
  def list: (Array[String] package_specs) -> void
35
35
 
36
36
  def list_lines: (String name, Hash[String, Array[String]] versions_by_registry) -> Array[String]
37
+
38
+ def sync: (Array[String] package_specs) -> void
37
39
  end
38
40
  end
@@ -12,6 +12,8 @@ module FhirPackagesManager
12
12
 
13
13
  def ignored?: () -> bool
14
14
 
15
+ def skipped?: () -> bool
16
+
15
17
  def not_found?: () -> bool
16
18
 
17
19
  def error?: () -> bool
@@ -16,14 +16,24 @@ module FhirPackagesManager
16
16
 
17
17
  def list_versions: (String name) -> Hash[String, Array[String]]
18
18
 
19
+ def sync: (String name) -> Array[FetchResult]
20
+
19
21
  private
20
22
 
21
23
  def fetch_package: (Package package) -> FetchResult
22
24
 
23
25
  def ignored?: (Package package) -> bool
24
26
 
25
- def download_result: (Package package, [Registry, String] found) -> FetchResult
26
-
27
27
  def available_versions: (Registry registry, String name) -> Array[String]
28
+
29
+ def raw_versions: (Registry registry, String name) -> Array[String]
30
+
31
+ def candidate_versions: (String name) -> Array[String]
32
+
33
+ def sync_version: (Package package) -> FetchResult
34
+
35
+ def download_path: (Package package) -> String
36
+
37
+ def download_result: (Package package, [Registry, String] found) -> FetchResult
28
38
  end
29
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fhir_packages_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Rozhkov