jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/424866 )
Change subject: [IMPR] Check for user-password.py too ......................................................................
[IMPR] Check for user-password.py too
- check for both user-config.py and user-password.py before create_user_config is called to prevent overwriting them - use constants for user-config.py and user-password.py basenames . simplify change_base_dir break statement - use textwrap.fill instead of textwrap.wrap - file_exists shows the message whether a file exists in a given directory from the old main part - also use textwrap.fill for the input message if the language code is missing in the known_langs list to wrap the text - use explicit parameters in create_user_config instead of packing and unpacking them - args are always given in create_user_config, we haven't to check for None - introduce userlist to hold the user tuple instead of reassignment uf usernames with a string later - use a "repeat" construction instead of pure a "while" to get_site_and_lang to prevent code duplication - use a single message formatted with textwrap.fill to show further informations about BotPassword. Clear the message later. - use a set to ensure different user names instead of filling the seen collector - ask for directory to change in ask_for_dir_change function which also checks whether both related files exists already and return booleans - pass KeybordInterrupt in a user-friendly way
Bug: T167573 Change-Id: I2f34f04354c13bde0dcb686e602a0d73394382c4 --- M generate_user_files.py 1 file changed, 115 insertions(+), 106 deletions(-)
Approvals: Framawiki: Looks good to me, approved jenkins-bot: Verified
diff --git a/generate_user_files.py b/generate_user_files.py index 5c62f78..77bd611 100755 --- a/generate_user_files.py +++ b/generate_user_files.py @@ -9,11 +9,12 @@ from __future__ import absolute_import, unicode_literals
import codecs +from collections import namedtuple import os import re import sys
-from textwrap import wrap +from textwrap import fill from warnings import warn
# Disable user-config usage as we are creating it here @@ -38,6 +39,9 @@ if console_encoding is None or sys.platform == 'cygwin': console_encoding = "iso-8859-1"
+USER_BASENAME = 'user-config.py' +PASS_BASENAME = 'user-password.py' +
def change_base_dir(): """Create a new user directory.""" @@ -53,7 +57,6 @@ pywikibot.error("directory access restricted") continue pywikibot.output("Using existing directory") - break else: try: os.mkdir(new_base, pywikibot.config2.private_files_permission) @@ -61,20 +64,19 @@ pywikibot.error('directory creation failed: {0}'.format(e)) continue pywikibot.output("Created new directory.") - break + break
if new_base == pywikibot.config2.get_base_dir(new_base): # config would find that file return new_base
- msg = wrap(u"""WARNING: Your user files will be created in the directory + msg = fill("""WARNING: Your user files will be created in the directory '%(new_base)s' you have chosen. To access these files, you will either have to use the argument "-dir:%(new_base)s" every time you run the bot, or set the environment variable "PYWIKIBOT2_DIR" equal to this directory name in your operating system. See your operating system documentation for how to set environment variables.""" % {'new_base': new_base}, width=76) - for line in msg: - pywikibot.output(line) + pywikibot.output(msg) if pywikibot.input_yn('Is this OK?', default=False, automatic_quit=False): return new_base pywikibot.output("Aborting changes.") @@ -84,7 +86,8 @@ def file_exists(filename): """Return whether the file exists and print a message if it exists.""" if os.path.exists(filename): - pywikibot.output(u"'%s' already exists." % filename) + pywikibot.output('{1} already exists in the target directory "{0}".' + .format(*os.path.split(filename))) return True return False
@@ -126,7 +129,8 @@ known_langs = []
if len(known_langs) == 0: - pywikibot.output('There were no known languages found in {0}.'.format(fam.name)) + pywikibot.output('There were no known languages found in {}.' + .format(fam.name)) default_lang = None elif len(known_langs) == 1: pywikibot.output('The only known language: {0}'.format(known_langs[0])) @@ -139,16 +143,16 @@ default_lang = 'en' else: default_lang = None - message = "The language code of the site we're working on"
+ message = "The language code of the site we're working on" mycode = None while not mycode: mycode = pywikibot.input(message, default=default_lang, force=force) if known_langs and mycode and mycode not in known_langs: - if not pywikibot.input_yn("The language code {0} is not in the " - "list of known languages. Do you want " - "to continue?".format(mycode), - default=False, automatic_quit=False): + if not pywikibot.input_yn( + fill('The language code {} is not in the list of known ' + 'languages. Do you want to continue?'.format(mycode)), + default=False, automatic_quit=False): mycode = None
message = 'Username on {0}:{1}'.format(mycode, fam.name) @@ -230,74 +234,65 @@ {botpasswords}"""
-def create_user_config(args=None, force=False): +def create_user_config(main_family, main_code, main_username, force=False): """ Create a user-config.py in base_dir.
Create a user-password.py if necessary. """ - _fnc = os.path.join(base_dir, "user-config.py") - _fncpass = os.path.join(base_dir, 'user-password.py') - if file_exists(_fnc): - return + _fnc = os.path.join(base_dir, USER_BASENAME) + _fncpass = os.path.join(base_dir, PASS_BASENAME)
- if args and force and not config.verbose_output: - # main_username may be None, which is used in the next block - main_family, main_code, main_username = args - usernames = [args] + useritem = namedtuple('useritem', 'family, code, name') + userlist = [] + if force and not config.verbose_output: + if main_username: + userlist = [useritem(main_family, main_code, main_username)] else: - main_family, main_code, main_username = get_site_and_lang(*args, - force=force) - usernames = [(main_family, main_code, main_username)] + while True: + userlist += [useritem(*get_site_and_lang( + main_family, main_code, main_username, force=force))] + if not pywikibot.input_yn('Do you want to add any other projects?', + force=force, + default=False, automatic_quit=False): + break
- while pywikibot.input_yn("Do you want to add any other projects?", - force=force, - default=False, automatic_quit=False): - usernames += [get_site_and_lang(main_family, main_code, - main_username)] - + # For each different username entered, ask if user wants to save a + # BotPassword (username, BotPassword name, BotPassword pass) + msg = fill('See https://www.mediawiki.org/wiki/' + 'Manual:Pywikibot/BotPasswords to know how to get codes.' + 'Please note that plain text in {} and anyone with read ' + 'access to that directory will be able read the file.' + .format(_fncpass)) botpasswords = [] - if not main_username: - usernames = "# usernames['{0}']['{1}'] = u'MyUsername'".format( - main_family, main_code) - elif not file_exists(_fncpass): - # For each different username entered, ask if user wants to save a - # BotPassword (username, BotPassword name, BotPassword pass) - seen = set() - for username in usernames: - if username[2] in seen: - continue - seen.add(username[2]) - if pywikibot.input_yn('Do you want to add a BotPassword for {0}?' - .format(username[2]), - force=force, default=False): - if not botpasswords: - pywikibot.output( - 'See https://www.mediawiki.org/wiki/' - 'Manual:Pywikibot/BotPasswords to know ' - 'how to get codes.') - pywikibot.output('Please note that plain text in {0} and ' - 'anyone with read access to that ' - 'directory will be able read the file.' - .format(_fncpass)) - message = 'BotPassword's "bot name" for {0}'.format( - username[2]) - botpasswordname = pywikibot.input(message, force=force) - message = 'BotPassword's "password" for BotPassword "{0}" ' \ - '(no characters will be shown)' \ - .format(botpasswordname) - botpasswordpass = pywikibot.input(message, force=force, - password=True) - if botpasswordname and botpasswordpass: - botpasswords.append((username[2], botpasswordname, - botpasswordpass)) + userset = {user.name for user in userlist} + for username in userset: + if pywikibot.input_yn('Do you want to add a BotPassword for {}?' + .format(username), force=force, default=False): + if msg: + pywikibot.output(msg) + msg = None + message = 'BotPassword's "bot name" for {}'.format(username) + botpasswordname = pywikibot.input(message, force=force) + message = 'BotPassword's "password" for "{}" ' \ + '(no characters will be shown)' \ + .format(botpasswordname) + botpasswordpass = pywikibot.input(message, force=force, + password=True) + if botpasswordname and botpasswordpass: + botpasswords.append((username, botpasswordname, + botpasswordpass))
+ if not userlist: # Show a sample + usernames = "# usernames['{}']['{}'] = u'MyUsername'".format( + main_family, main_code) + else: usernames = '\n'.join( - u"usernames['{0}']['{1}'] = u'{2}'".format(*username) - for username in usernames) - botpasswords = '\n'.join( - "('{0}', BotPassword('{1}', '{2}'))".format(*botpassword) - for botpassword in botpasswords) + "usernames['{user.family}']['{user.code}'] = u'{user.name}'" + .format(user=user) for user in userlist) + botpasswords = '\n'.join( + "('{0}', BotPassword('{1}', '{2}'))".format(*botpassword) + for botpassword in botpasswords)
config_text = '' config_content = SMALL_CONFIG @@ -346,14 +341,14 @@ try: # Finally save user-config.py with codecs.open(_fnc, "w", "utf-8") as f: - f.write(config_content.format(main_family=main_family, - main_code=main_code, - usernames=usernames, - config_text=config_text, - botpasswords='password_file = ' + - ('"user-password.py"' - if botpasswords - else 'None'))) + f.write(config_content.format( + main_family=main_family, + main_code=main_code, + usernames=usernames, + config_text=config_text, + botpasswords='password_file = ' + ('"{}"'.format(PASS_BASENAME) + if botpasswords + else 'None'))) pywikibot.output(u"'%s' written." % _fnc) except BaseException: if os.path.exists(_fnc): @@ -378,6 +373,38 @@ raise
+def ask_for_dir_change(force): + """Ask whether the base directory is has to be changed. + + Only give option for directory change if user-config.py or user-password + already exists in the directory. This will repeat if user-config.py also + exists in the requested directory. + + @param force: Skip asking for directory change + @type force: bool + @return: whether user file or password file exists already + @rtype: tuple of bool + """ + global base_dir + + pywikibot.output('\nYour default user directory is "{}"'.format(base_dir)) + while True: + # Show whether file exists + userfile = file_exists(os.path.join(base_dir, USER_BASENAME)) + passfile = file_exists(os.path.join(base_dir, PASS_BASENAME)) + if force and not config.verbose_output or not (userfile or passfile): + break + if pywikibot.input_yn( + 'Would you like to change the directory?', + default=True, automatic_quit=False, force=force): + new_base = change_base_dir() + if new_base: + base_dir = new_base + else: + break + return userfile, passfile + + def main(*args): """ Process command line arguments and generate user-config. @@ -395,49 +422,31 @@ # and 'force' mode can be activated below. (config.family, config.mylang) = ('wikipedia', None)
- pywikibot.output('You can abort at any time by pressing ctrl-c') - local_args = pywikibot.handle_args(args) if local_args: pywikibot.output('Unknown arguments: %s' % ' '.join(local_args)) return False
+ pywikibot.output('You can abort at any time by pressing ctrl-c') if config.mylang is not None: force = True pywikibot.output(u'Automatically generating user-config.py') else: force = False # Force default site of en.wikipedia - (config.family, config.mylang) = ('wikipedia', 'en') + config.family, config.mylang = 'wikipedia', 'en'
username = config.usernames[config.family].get(config.mylang) - args = (config.family, config.mylang, username)
- # Only give option for directory change if user-config.py already exists - # in the directory. This will repeat if user-config.py also exists in - # the requested directory. - # TODO: T167573: check for user-password.py too - if not force or config.verbose_output: - pywikibot.output(u'\nYour default user directory is "%s"' % base_dir) - while os.path.isfile(os.path.join(base_dir, "user-config.py")): - pywikibot.output('user-config.py already exists' - ' in the target directory.') - if pywikibot.input_yn('Would you like to change the directory?', - default=True, - automatic_quit=False, force=force): - new_base = change_base_dir() - if new_base: - base_dir = new_base - else: - break + try: + has_userfile, has_passfile = ask_for_dir_change(force) + if not (has_userfile or has_userfile): + create_user_config(config.family, config.mylang, username, + force=force) + except KeyboardInterrupt: + pywikibot.output('\nScript terminated by user.')
- # user-fixes.py also used to be created here, but has - # been replaced by an example file. - if not os.path.isfile(os.path.join(base_dir, "user-config.py")): - create_user_config(args, force=force) - else: - pywikibot.output('user-config.py already exists in the target ' - 'directory "{0}".'.format(base_dir)) + # Creation of user-fixes.py has been replaced by an example file.
if __name__ == '__main__':
pywikibot-commits@lists.wikimedia.org