Skip to content

Commit b51b115

Browse files
committed
Feat: Add merge cmd for multiple maven zips
1 parent 49a67e1 commit b51b115

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

charon/cmd/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from charon.cmd.cmd_checksum import init_checksum, checksum
2121
from charon.cmd.cmd_cache import init_cf, cf
2222
from charon.cmd.cmd_sign import sign
23+
from charon.cmd.cmd_merge import merge
2324

2425

2526
@group()
@@ -47,3 +48,6 @@ def cli(ctx):
4748

4849
# radas sign cmd
4950
cli.add_command(sign)
51+
52+
# maven zips merge cmd
53+
cli.add_command(merge)

charon/cmd/cmd_merge.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"""
2+
Copyright (C) 2022 Red Hat, Inc. (https://github.com/Commonjava/charon)
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
"""
16+
from typing import List
17+
18+
from charon.utils.archive import detect_npm_archives, NpmArchiveType
19+
from charon.cmd.internal import _get_local_repos, _decide_mode
20+
from charon.pkgs.maven import _extract_tarballs
21+
from click import command, option, argument
22+
from zipfile import ZipFile, ZIP_DEFLATED
23+
from tempfile import mkdtemp
24+
25+
import logging
26+
import os
27+
import sys
28+
29+
logger = logging.getLogger(__name__)
30+
31+
32+
@argument(
33+
"repos",
34+
type=str,
35+
nargs=-1 # This allows multiple arguments for zip urls
36+
)
37+
@option(
38+
"--product",
39+
"-p",
40+
help="""
41+
The product key, will combine with version to decide
42+
the metadata of the files in tarball.
43+
""",
44+
nargs=1,
45+
required=True,
46+
multiple=False,
47+
)
48+
@option(
49+
"--version",
50+
"-v",
51+
help="""
52+
The product version, will combine with key to decide
53+
the metadata of the files in tarball.
54+
""",
55+
required=True,
56+
multiple=False,
57+
)
58+
@option(
59+
"--root_path",
60+
"-r",
61+
default="maven-repository",
62+
help="""
63+
The root path in the tarball before the real maven paths,
64+
will be trailing off before uploading.
65+
""",
66+
)
67+
@option(
68+
"--work_dir",
69+
"-w",
70+
help="""
71+
The temporary working directory into which archives should
72+
be extracted, when needed.
73+
""",
74+
)
75+
@option(
76+
"--merge_result",
77+
"-m",
78+
help="""
79+
The path of the final merged zip file will be compressed and saved.
80+
""",
81+
)
82+
@option(
83+
"--debug",
84+
"-D",
85+
help="Debug mode, will print all debug logs for problem tracking.",
86+
is_flag=True,
87+
default=False
88+
)
89+
@option(
90+
"--quiet",
91+
"-q",
92+
help="Quiet mode, will shrink most of the logs except warning and errors.",
93+
is_flag=True,
94+
default=False
95+
)
96+
@command()
97+
def merge(
98+
repos: List[str],
99+
product: str,
100+
version: str,
101+
root_path="maven-repository",
102+
work_dir=None,
103+
merge_result=None,
104+
debug=False,
105+
quiet=False
106+
):
107+
"""Merge multiple Maven ZIP archives and compress the result into a single ZIP file.
108+
The merged file is stored locally as specified by merge_result.
109+
110+
Note: This function does not support merging single archive, NPM archives,
111+
or archives of inconsistent types.
112+
"""
113+
_decide_mode(product, version, is_quiet=quiet, is_debug=debug)
114+
if len(repos) == 1:
115+
logger.info("Skip merge step, single archive detected, no merge needed")
116+
sys.exit(0)
117+
118+
product_key = f"{product}-{version}"
119+
archive_paths = _get_local_repos(repos)
120+
archive_types = detect_npm_archives(archive_paths)
121+
122+
maven_count = archive_types.count(NpmArchiveType.NOT_NPM)
123+
npm_count = len(archive_types) - maven_count
124+
if maven_count == len(archive_types):
125+
tmp_root = _extract_tarballs(archive_paths, root_path, product_key, dir__=work_dir)
126+
_create_merged_zip(tmp_root, merge_result, product_key, work_dir)
127+
elif npm_count == len(archive_types):
128+
logger.error("Skip merge step for the npm archives")
129+
sys.exit(1)
130+
else:
131+
logger.error("Skip merge step since the types are not consistent")
132+
sys.exit(1)
133+
134+
135+
def _create_merged_zip(
136+
root_path: str,
137+
merge_result: str,
138+
product_key: str,
139+
work_dir: str
140+
):
141+
zip_path = merge_result
142+
if not merge_result:
143+
merge_path = mkdtemp(prefix=f"{product_key}_merged_", dir=work_dir)
144+
zip_path = os.path.join(merge_path, f"{product_key}_merged.zip")
145+
146+
# pylint: disable=unused-variable
147+
with ZipFile(zip_path, 'w', ZIP_DEFLATED) as zipf:
148+
for root, dirs, files in os.walk(root_path):
149+
for file in files:
150+
file_path = os.path.join(root, file)
151+
# Calculate relative path to preserve directory structure
152+
arcname = os.path.relpath(file_path, root_path)
153+
zipf.write(file_path, arcname)
154+
logger.info("Done for the merged zip generation: %s", zip_path)

0 commit comments

Comments
 (0)