Index

s3-bsync / a3ba179

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

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
1116 Jun 2022 12:49a3ba179Update help text and READMEJosh Stockin12920G

Blob @ s3-bsync / src / command_parse.py

application/x-python5583 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 "--help", "-h", "-?", action="help", help="Display this help message and exit."
42 )
43 parser.add_argument(
44 "--version",
45 "-v",
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 "--init",
59 "-i",
60 action="store_true",
61 default=False,
62 help="Run in initialize (edit) 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 "--dryrun",
72 action="store_true",
73 default=False,
74 help="Run program logic without making changes. Useful when paired with debug mode to see what changes would be made.",
75 )
76
77 group2 = parser.add_argument_group(
78 "tracking file management", "Configuring the tracking file."
79 )
80
81 group2.add_argument(
82 "--file",
83 nargs=1,
84 metavar=("SYNCFILE"),
85 default=["~/.state.s3sync"],
86 help="The s3sync state file used to store tracking and state information. It should resolve to an absolute path.",
87 )
88 group2.add_argument(
89 "--dump",
90 action="store_true",
91 default=False,
92 help="Dump s3sync state file configuration and exit.",
93 )
94 group2.add_argument(
95 "--purge",
96 action="store_true",
97 default=False,
98 help="Deletes the tracking configuration file if it exists and exits. Requires init mode.",
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. Requires init mode.",
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 group3.add_argument(
123 "--rmdir",
124 action="append",
125 nargs=1,
126 metavar=("RMPATH"),
127 default=argparse.SUPPRESS,
128 help="Remove tracked directory map by local directory identifier. Running "
129 "`--rmdir /home/josh/Documents` would remove the directory map from the s3sync"
130 "file and stop tracking/syncing that directory.",
131 )
132 return parser.parse_args(args)
133
134
135def sanitize_arguments(args: argparse.Namespace):
136 if args.debug:
137 logger.debug("DEBUG mode set")
138
139 if args.init:
140 logger.debug("INIT mode set")
141 else:
142 logger.debug("SYNC mode set implicitly (INIT not set)")
143
144 if args.dryrun:
145 logger.debug("DRYRUN mode set")
146
147 logger.debug(f'User supplied tracking file "{args.file[0]}". Sanitizing...')
148 whitespace_pattern = re.compile(r"\s+")
149 args.file = os.path.expanduser(args.file[0])
150 args.file = re.sub(whitespace_pattern, "", args.file)
151 if not args.file:
152 logger.error("Inputted tracking file path string is empty")
153 exit(1)
154 if not os.path.isabs(args.file):
155 logger.error("Inputted tracking file path is not an absolute path")
156 exit(1)
157 if os.path.isdir(args.file):
158 logger.error("Inputted tracking file path resolves to an existing directory")
159 exit(1)
160 logger.debug(f'Tracking file set to "{args.file}"')
161
162 if args.purge:
163 if args.init:
164 logger.debug("PURGE mode set")
165 else:
166 logger.debug("PURGE mode set, but INIT mode isn't. Ignoring")
167
168 if args.overwrite:
169 if args.init:
170 logger.debug("OVERWRITE mode set")
171 else:
172 logger.debug("OVERWRITE mode set, but INIT mode isn't. Ignoring")
173
174 return args
175