Index

s3-bsync / 94fa0b0

Bidirectional syncing tool to sync local filesystem directories with S3 buckets. (Incomplete)

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
1016 Jun 2022 12:0894fa0b0Clean up repo, begin work on class abstraction and serializationJosh Stockin13022G

Blob @ s3-bsync / src / command_parse.py

application/x-python5220 bytesdownload raw
1# s3-bsync Copyright (c) 2021 Joshua Stockin
2# <https://joshstock.in>
3# <https://git.joshstock.in/s3-bsync>
4#
5# This software is licensed and distributed under the terms of the MIT License.
6# See the MIT License in the LICENSE file of this project's root folder.
7#
8# This comment block and its contents, including this disclaimer, MUST be
9# preserved in all copies or distributions of this software's source.
10
11import os
12import re
13import argparse
14
15import logging
16
17from .meta import package_info
18
19logger = logging.getLogger(__name__)
20
21__all__ = ["command_parse", "sanitize_arguments"]
22
23
24def command_parse(args: list[str]):
25 class Formatter(
26 argparse.RawDescriptionHelpFormatter,
27 argparse.ArgumentDefaultsHelpFormatter,
28 argparse.HelpFormatter,
29 ):
30 pass
31
32 parser = argparse.ArgumentParser(
33 prog=package_info["name"],
34 description=package_info["description"],
35 formatter_class=lambda prog: Formatter(prog, width=88),
36 allow_abbrev=False,
37 add_help=False,
38 )
39
40 parser.add_argument(
41 "-h", "-?", "--help", action="help", help="Display this help message and exit."
42 )
43 parser.add_argument(
44 "-v",
45 "--version",
46 action="version",
47 help="Display program and version information and exit.",
48 version=f"s3-bsync version {package_info['version_string']}\n"
49 "<https://joshstock.in> <josh@joshstock.in>\n"
50 "<https://git.joshstock.in/s3-bsync>",
51 )
52
53 group1 = parser.add_argument_group(
54 "program behavior", "The program runs in sync mode by default."
55 )
56
57 group1.add_argument(
58 "-i",
59 "--init",
60 action="store_true",
61 default=False,
62 help="Run in initialize mode. This allows tracking file management and directory options to be used.",
63 )
64 group1.add_argument(
65 "--debug",
66 action="store_true",
67 default=False,
68 help="Enables debug mode, which prints program information to stdout.",
69 )
70 group1.add_argument(
71 "--file",
72 nargs=1,
73 metavar=("SYNCFILE"),
74 default=["~/.state.s3sync"],
75 help="The s3sync state file used to store tracking and state information. It should resolve to an absolute path.",
76 )
77 group1.add_argument(
78 "--dump",
79 action="store_true",
80 default=False,
81 help="Dump s3sync state file configuration. --dryrun implicitly enabled.",
82 )
83 group1.add_argument(
84 "--dryrun",
85 action="store_true",
86 default=False,
87 help="Run program logic without making changes. Useful when paired with debug mode to see what changes would be made.",
88 )
89
90 group2 = parser.add_argument_group(
91 "tracking file management", "Requires initialize mode to be enabled."
92 )
93
94 group2.add_argument(
95 "--purge",
96 action="store_true",
97 default=False,
98 help="Deletes the default (if not otherwise specified with --file) tracking configuration file if it exists.",
99 )
100 group2.add_argument(
101 "--overwrite",
102 action="store_true",
103 default=False,
104 help="Overwrite tracking file with new directory maps instead of appending.",
105 )
106
107 group3 = parser.add_argument_group(
108 "directory mapping", "Requires initialize mode to be enabled."
109 )
110
111 group3.add_argument(
112 "--dir",
113 action="append",
114 nargs=2,
115 metavar=("PATH", "S3_DEST"),
116 default=argparse.SUPPRESS,
117 help="Directory map to detail which local directory corresponds to S3 bucket "
118 "and key prefix. Can be used multiple times to set multiple directories. "
119 "Local directories must be absolute. S3 destination in `s3://bucket-name/prefix` "
120 "format. Example: `--dir /home/josh/Documents s3://joshstockin/Documents`",
121 )
122
123 return parser.parse_args(args)
124
125
126def sanitize_arguments(args: argparse.Namespace):
127 if args.debug:
128 logger.debug("DEBUG mode set")
129
130 if args.init:
131 logger.debug("INIT mode set")
132 else:
133 logger.debug("SYNC mode set implicitly (INIT not set)")
134
135 if args.dryrun:
136 logger.debug("DRYRUN mode set")
137
138 logger.debug(f'User supplied tracking file "{args.file[0]}". Sanitizing...')
139 whitespace_pattern = re.compile(r"\s+")
140 args.file = os.path.expanduser(args.file[0])
141 args.file = re.sub(whitespace_pattern, "", args.file)
142 if not args.file:
143 logger.error("Inputted tracking file path string is empty")
144 exit(1)
145 if not os.path.isabs(args.file):
146 logger.error("Inputted tracking file path is not an absolute path")
147 exit(1)
148 if os.path.isdir(args.file):
149 logger.error("Inputted tracking file path resolves to an existing directory")
150 exit(1)
151 logger.debug(f'Tracking file set to "{args.file}"')
152
153 if args.purge:
154 if args.init:
155 logger.debug("PURGE mode set")
156 else:
157 logger.debug("PURGE mode set, but INIT mode isn't. Ignoring")
158
159 if args.overwrite:
160 if args.init:
161 logger.debug("OVERWRITE mode set")
162 else:
163 logger.debug("OVERWRITE mode set, but INIT mode isn't. Ignoring")
164
165 return args
166