Index

s3-bsync / bfb1fb4

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

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
1216 Jun 2022 14:26bfb1fb4Update module handling and settingsJosh Stockin1336G

Blob @ s3-bsync / src / command_parse.py

application/x-python6342 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
14import logging
15
16from .meta import package_info
17
18logger = logging.getLogger(__name__)
19
20__all__ = ["command_parse", "sanitize_arguments"]
21
22
23def command_parse(args: list[str]):
24 class Formatter(
25 argparse.RawDescriptionHelpFormatter,
26 argparse.ArgumentDefaultsHelpFormatter,
27 argparse.HelpFormatter,
28 ):
29 pass
30
31 parser = argparse.ArgumentParser(
32 prog=package_info["name"],
33 description=package_info["description"],
34 formatter_class=lambda prog: Formatter(prog, width=88),
35 allow_abbrev=False,
36 add_help=False,
37 )
38
39 parser.add_argument(
40 "--help", "-h", "-?", action="help", help="Display this help message and exit."
41 )
42 parser.add_argument(
43 "--version",
44 "-v",
45 action="version",
46 help="Display program and version information and exit.",
47 version=f"s3-bsync version {package_info['version_string']}\n"
48 "<https://joshstock.in> <josh@joshstock.in>\n"
49 "<https://git.joshstock.in/s3-bsync>",
50 )
51
52 group1 = parser.add_argument_group(
53 "program behavior", "The program runs in sync mode by default."
54 )
55
56 group1.add_argument(
57 "--init",
58 "-i",
59 action="store_true",
60 default=False,
61 help="Run in initialize (edit) mode. This allows tracking file management and directory options to be used.",
62 )
63 group1.add_argument(
64 "--debug",
65 action="store_true",
66 default=False,
67 help="Enables debug flag, which prints program information to stdout.",
68 )
69 group1.add_argument(
70 "--dryrun",
71 action="store_true",
72 default=False,
73 help="Run program logic without making changes. Useful when paired with debug mode to see what changes would be made.",
74 )
75
76 group2 = parser.add_argument_group(
77 "tracking file management", "Configuring the tracking file."
78 )
79
80 group2.add_argument(
81 "--file",
82 nargs=1,
83 metavar=("SYNCFILE"),
84 default=["~/.state.s3sync"],
85 help="The s3sync state file used to store tracking and state information. It should resolve to an absolute path.",
86 )
87 group2.add_argument(
88 "--dump",
89 action="store_true",
90 default=False,
91 help="Dump s3sync state file configuration and exit.",
92 )
93 group2.add_argument(
94 "--purge",
95 action="store_true",
96 default=False,
97 help="Deletes the tracking configuration file if it exists and exits. Requires init mode.",
98 )
99 group2.add_argument(
100 "--overwrite",
101 action="store_true",
102 default=False,
103 help="Overwrite tracking file with new directory maps instead of appending. Requires init mode.",
104 )
105
106 group3 = parser.add_argument_group(
107 "directory mapping", "Requires initialize mode to be enabled."
108 )
109
110 group3.add_argument(
111 "--dir",
112 action="append",
113 nargs=2,
114 metavar=("PATH", "S3_DEST"),
115 default=argparse.SUPPRESS,
116 help="Directory map to detail which local directory corresponds to S3 bucket "
117 "and key prefix. Can be used multiple times to set multiple directories. "
118 "Local directories must be absolute. S3 destination in `s3://bucket-name/prefix` "
119 "format. Example: `--dir /home/josh/Documents s3://joshstockin/Documents`",
120 )
121 group3.add_argument(
122 "--rmdir",
123 action="append",
124 nargs=1,
125 metavar=("RMPATH"),
126 default=argparse.SUPPRESS,
127 help="Remove tracked directory map by local directory identifier. Running "
128 "`--rmdir /home/josh/Documents` would remove the directory map from the s3sync"
129 "file and stop tracking/syncing that directory.",
130 )
131 return parser.parse_args(args)
132
133
134class sync_settings:
135 def __init__(self, **kwargs):
136 self.__dict__.update(kwargs)
137
138
139def sanitize_arguments(args: argparse.Namespace):
140 settings = sync_settings(debug=False, mode="SYNC")
141
142 if args.debug:
143 logger.debug("DEBUG flag set")
144 settings.debug = True
145
146 if args.init:
147 logger.debug("INIT mode set")
148 settings.mode = "INIT"
149 else:
150 logger.debug("SYNC mode set implicitly (INIT not set)")
151 settings.mode = "SYNC"
152
153 if args.dryrun:
154 logger.debug("DRYRUN mode set")
155 settings.mode = "DRYRUN"
156
157 logger.debug(f'User supplied tracking file "{args.file[0]}". Sanitizing...')
158 whitespace_pattern = re.compile(r"\s+")
159 args.file = os.path.expanduser(args.file[0])
160 args.file = re.sub(whitespace_pattern, "", args.file)
161 if not args.file:
162 logger.error("Inputted tracking file path string is empty")
163 exit(1)
164 if not os.path.isabs(args.file):
165 logger.error("Inputted tracking file path is not an absolute path")
166 exit(1)
167 if os.path.isdir(args.file):
168 logger.error("Inputted tracking file path resolves to an existing directory")
169 exit(1)
170 logger.debug(f'Tracking file set to "{args.file}"')
171 settings.syncfile = args.file
172
173 if args.purge:
174 if args.init:
175 logger.debug("PURGE mode set")
176 settings.mode = "PURGE"
177 else:
178 logger.debug("PURGE flag set, but INIT mode isn't. Ignoring")
179
180 if args.dump:
181 logger.debug("DUMP mode set")
182 settings.mode = "DUMP"
183
184 if args.overwrite:
185 if args.init:
186 logger.debug("OVERWRITE mode set")
187 settings.mode = "OVERWRITE"
188 else:
189 logger.debug("OVERWRITE flag set, but INIT mode isn't. Ignoring")
190
191 if hasattr(args, "dir"):
192 settings.dirmaps = {}
193 for dirmap in args.dir:
194 settings.dirmaps[dirmap[0]] = dirmap[1]
195
196 if hasattr(args, "rmdir"):
197 settings.rmdirs = []
198 for rmdir in args.rmdir:
199 settings.rmdirs.append(rmdir[0])
200
201 return settings
202