def update_crate_repositories_branches(args, temp_dir, repositories): write_msg('=> Merging "master" branches into "crate" branches...') for repo in repositories: merging_branches(repo, temp_dir, "master") write_msg('Done!') write_msg('=> Updating [crate] crates version...') for crate in args.crates: crate = crate['crate'] if args.specified_crate is not None and crate[ 'crate'] != args.specified_crate: continue if update_crate_version(crate["repository"], crate["crate"], crate["path"], temp_dir, args.specified_crate) is False: write_error('The update for the "{}" crate failed...'.format( crate["crate"])) return False write_msg('Done!') write_msg('=> Committing{} to the "{}" branch...'.format( " and pushing" if args.no_push is False else "", consts.CRATE_TMP_BRANCH)) for repo in repositories: commit(repo, temp_dir, "Update versions [ci skip]") if args.no_push is False: push(repo, temp_dir, consts.CRATE_TMP_BRANCH) write_msg('Done!') if args.no_push is False: write_msg('=> Creating PRs on crate branch...') for repo in repositories: create_pull_request(repo, consts.CRATE_TMP_BRANCH, "crate", args.token) write_msg('Done!') return True
def update_crates_versions(args, temp_dir, repositories): write_msg('=> Updating [master] crates version...') for crate in args.crates: update_type = crate['up-type'] crate = crate['crate'] if args.specified_crate is not None and crate[ 'crate'] != args.specified_crate: continue if update_repo_version(crate["repository"], crate["crate"], crate["path"], temp_dir, update_type, args.badges_only or args.tags_only) is False: write_error('The update for the "{}" crate failed...'.format( crate["crate"])) return False write_msg('Done!') if args.badges_only is False and args.tags_only is False: write_msg('=> Committing{} to the "{}" branch...'.format( " and pushing" if args.no_push is False else "", consts.MASTER_TMP_BRANCH)) for repo in repositories: commit(repo, temp_dir, "Update versions [ci skip]") if args.no_push is False: push(repo, temp_dir, consts.MASTER_TMP_BRANCH) write_msg('Done!') if args.no_push is False: write_msg('=> Creating PRs on master branch...') for repo in repositories: create_pull_request(repo, consts.MASTER_TMP_BRANCH, "master", args.token) write_msg('Done!') return True
def change_command(user): ws = get_worksheet() stored_row = "" try: if "-r" in sys.argv: row_number = int(get_argument(sys.argv, "-r")) if row_number and row_number >= 2: selected_row = ws.row_values(row_number) if user == selected_row[0]: stored_row = selected_row else: write_error("You can't edit others information") exit() else: write_error("Invalid row") exit() else: row_number = get_users_last_row(ws, user) stored_row = ws.row_values(row_number) display_loading_message("Updating info", "Information updated") new_date = get_date() if "-d" in sys.argv else stored_row[1] new_message = get_argument( sys.argv, "-m") if "-m" in sys.argv else stored_row[2] new_description = get_argument(sys.argv, "-t") if "-t" in sys.argv else stored_row[3] \ if len(stored_row) >= 4 else "" stored_row = [stored_row[0], new_date, new_message, new_description] update_row(ws, stored_row, row_number) hide_loading_message_with_error(False) except Exception: hide_loading_message_with_error(True) exit()
def switch(command, user, is_sudo): try: if command == "init": init_app() elif command == "write": startup_check() write_command(user) elif command == "read": startup_check() read_command() elif command == "share": startup_check() share_command() elif command == "change": startup_check() change_command(user) elif command == "version": version_command() elif command == "help": help_command() elif command == "delete": startup_check() delete_command(user, is_sudo) elif command == "reset": reset_command() else: write_error( "Command not found. For further informations use `servy help`") except KeyboardInterrupt: hide_loading_message_with_error(True, "\n")
def delete_command(user, is_sudo): ws = get_worksheet() if "-r" in sys.argv: row = int(get_argument(sys.argv, "-r")) if row >= 2: try: display_loading_message("Deleting message", "Message deleted") if int(is_sudo) != 0: selected_row = ws.row_values(row) if selected_row[0] and user != selected_row[0]: hide_loading_message_with_error( True, "You cannot delete rows written by other users") exit() delete_row(ws, row) hide_loading_message_with_error(False) except Exception: hide_loading_message_with_error(True) else: write_error("Invalid row") else: try: display_loading_message("Deleting message", "Message deleted") last_row = get_users_last_row(ws, user) delete_row(ws, last_row) hide_loading_message_with_error(False) except IndexError: hide_loading_message_with_error( True, "Error. No rows inserted by the current user")
def create_pull_request(repo_name, from_branch, target_branch, token): r = post_content( '{}/repos/{}/{}/pulls'.format(consts.GH_API_URL, consts.ORGANIZATION, repo_name), token, { 'title': '[release] merging {} into {}'.format(from_branch, target_branch), 'body': 'cc @GuillaumeGomez @EPashkin @sdroege', 'base': target_branch, 'head': from_branch, 'maintainer_can_modify': True }) if r is None: write_error( "Pull request from {repo}/{from_b} to {repo}/{target} couldn't be created. You " "need to do it yourself... (url provided at the end)".format( repo=repo_name, from_b=from_branch, target=target_branch)) input("Press ENTER once done to continue...") PULL_REQUESTS.append('|=> "{}/{}/{}/compare/{}...{}?expand=1"'.format( consts.GITHUB_URL, consts.ORGANIZATION, repo_name, target_branch, from_branch)) else: write_msg("===> Pull request created: {}".format(r['html_url'])) PULL_REQUESTS.append('> {}'.format(r['html_url']))
def update_version(version, update_type, section_name, place_type="section"): version_split = version.replace('"', '').split('.') if len(version_split) != 3: # houston, we've got a problem! write_error('Invalid version in {} "{}": {}'.format( place_type, section_name, version)) return None if update_type == UpdateType.MINOR: version_split[update_type] = str(int(version_split[update_type]) + 1) elif update_type == UpdateType.MEDIUM: version_split[update_type] = str(int(version_split[update_type]) + 1) version_split[UpdateType.MINOR] = '0' else: i = 0 for c in version_split[update_type]: if c >= '0' and c <= '9': break i += 1 if i >= len(c): return None s = version_split[update_type][i:] version_split[update_type] = '{}{}'.format( version_split[update_type][:i], str(int(s) + 1)) version_split[UpdateType.MEDIUM] = '0' version_split[UpdateType.MINOR] = '0' return '"{}"'.format('.'.join(version_split))
def update_doc_content_repository(repositories, temp_dir, token, no_push, args): if clone_repo(consts.DOC_CONTENT_REPO, temp_dir) is False: input('Try to fix the problem then press ENTER to continue...') write_msg("Done!") repo_path = join(temp_dir, consts.DOC_CONTENT_REPO) write_msg("=> Generating documentation for crates...") for repo in repositories: current = None for crate in args.crates: crate = crate['crate'] if crate['repository'] == repo: current = crate break if current is None: input( 'No repository matches "{}", something is weird. (Press ENTER TO CONTINUE)' ) continue if current.get("doc", True) is False: continue write_msg('==> Generating documentation for "{}"'.format(current)) path = join(temp_dir, current['repository']) command = [ 'bash', '-c', 'cd {} && make doc && mv vendor.md {}'.format( path, join(repo_path, current['crate'])) ] if not exec_command_and_print_error(command): input("Fix the error and then press ENTER") write_msg('Done!') write_msg('Committing "{}" changes...'.format(consts.DOC_CONTENT_REPO)) commit(consts.DOC_CONTENT_REPO, temp_dir, "Update vendor files") if no_push is False: push(consts.DOC_CONTENT_REPO, temp_dir, consts.MASTER_TMP_BRANCH) # We always make minor releases in here, no need for a more important one considering we don't # change the API. if update_repo_version(consts.DOC_CONTENT_REPO, consts.DOC_CONTENT_REPO, "", temp_dir, UpdateType.MINOR, False) is False: write_error('The update for the "{}" crate failed...'.format( consts.DOC_CONTENT_REPO)) input('Fix the error and then press ENTER') commit(consts.DOC_CONTENT_REPO, temp_dir, "Update version") if no_push is False: push(consts.DOC_CONTENT_REPO, temp_dir, consts.MASTER_TMP_BRANCH) create_pull_request(consts.DOC_CONTENT_REPO, consts.MASTER_TMP_BRANCH, "master", token, False) input(( 'All done with the "{}" update: please merge the PR then press ENTER so the ' 'publication can performed...').format(consts.DOC_CONTENT_REPO)) publish_crate(consts.DOC_CONTENT_REPO, "", temp_dir, consts.DOC_CONTENT_REPO, checkout_branch='master') write_msg('Ok all done! We can move forward now!') else: write_msg(( 'All with "{}", you still need to publish a new version if you want the changes ' 'to be taken into account').format(consts.DOC_CONTENT_REPO))
def share_command(): if "-l" in sys.argv: ss = get_spreadsheet() print_permissions(ss) elif "-a" in sys.argv: email = get_argument(sys.argv, "-a") if validate_email(email): try: display_loading_message("Adding permission", "Permission added") ss = get_spreadsheet() share_spreadsheet(ss, email) hide_loading_message_with_error(False) except Exception: hide_loading_message_with_error(True) else: write_error("Invalid email: " + email) elif "-d" in sys.argv: email = get_argument(sys.argv, "-d") if validate_email(email): try: display_loading_message("Removing permission", "Permission removed") ss = get_spreadsheet() ss.remove_permissions(email) hide_loading_message_with_error(False) except Exception: hide_loading_message_with_error(True) else: write_error("Invalid email: " + email)
def handle_error(self, req, client, addr, exc): request_start = time.time() addr = addr or ('', -1) if isinstance(exc, (InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, InvalidHeader, InvalidHeaderName, LimitRequestLine, LimitRequestHeaders, InvalidProxyLine, ForbiddenProxyRequest, SSLError)): status_int = 400 reason = "Bad Request" if isinstance(exc, InvalidRequestLine): msg = "Invalid request line: {!s}".format(exc) elif isinstance(exc, InvalidRequestMethod): msg = "Invalid method: {!s}".format(exc) elif isinstance(exc, InvalidHTTPVersion): msg = "Invalid http version: {!s}".format(exc) elif isinstance(exc, (InvalidHeaderName, InvalidHeader,)): msg = str(exc) if not req and hasattr(exc, "req"): req = exc.req elif isinstance(exc, LimitRequestLine): msg = str(exc) elif isinstance(exc, LimitRequestHeaders): msg = "Error parsing headers: {!s}".format(exc) elif isinstance(exc, SSLError): reason = "Forbidden" msg = str(exc) status_int = 403 msg = "Invalid request from ip={ip}: {error}" self.log.debug(msg.format(ip=addr[0], error=str(exc))) else: if hasattr(req, 'uri'): self.log.exception("Error hanling request {!s}".format(req.uri)) status_int = 500 reason = "Internal Server Error" msg = "" if req is not None: request_time = time.time() - request_start environ = default_environ(req, client, self.config) environ['REMOTE_ADDR'] = addr[0] environ['REMOTE_PORT'] = str(addr[1]) resp = Response(req, client, self.config) resp.status = "{} {}".format(status_int, reason) resp.length = len(msg) self.log.access(resp, req, environ, request_time) try: write_error(client, status_int, reason, msg) except Exception: self.log.debug("Failed to send error message.")
def build_docs(repo_name, temp_dir): path = join(temp_dir, repo_name) features = get_features(join(path, 'Cargo.toml')) command = [ 'bash', '-c', 'cd {} && cargo doc --no-default-features --features "{}"'.format( path, features) ] if not exec_command_and_print_error(command): input( "Couldn't generate docs! Try to fix it and then press ENTER to continue..." ) doc_folder = join(path, 'target/doc') try: file_list = ' '.join([ '"{}"'.format(f) for f in listdir(doc_folder) if isfile(join(doc_folder, f)) ]) except Exception as e: write_error('Error occured in build docs: {}'.format(e)) input( "It seems like the \"{}\" folder doesn't exist. Try to fix it then press ENTER..." .format(doc_folder)) command = [ 'bash', '-c', 'cd {} && cp -r "{}" src/{} {} "{}"'.format( doc_folder, repo_name.replace('-', '_'), repo_name.replace('-', '_'), file_list, join(temp_dir, consts.DOC_REPO)) ] if not exec_command_and_print_error(command): input( "Couldn't copy docs! Try to fix it and then press ENTER to continue..." ) lines = get_file_content(join(path, 'target/doc/search-index.js')).split('\n') before = True fill_extras = len(SEARCH_INDEX_BEFORE) == 0 for line in lines: if line.startswith('searchIndex['): before = False # We need to be careful in here if we're in a sys repository (which should never be the # case!). if line.startswith('searchIndex["{}"]'.format( repo_name.replace('-', '_'))): SEARCH_INDEX.append(line) elif fill_extras is True: if before is True: SEARCH_INDEX_BEFORE.append(line) else: SEARCH_INDEX_AFTER.append(line) input( "Couldn't find \"{}\" in `searchIndex.js`! Try to fix it and then press ENTER to \ continue...".format(repo_name.replace('-', '_')))
def append_default_spreadsheet(credentials_path, default_spreadsheet): with open(credentials_path, "r+") as credentials: try: credentials_json = load(credentials) credentials_json["default_spreadsheet"] = default_spreadsheet credentials.seek(0, 0) dump(credentials_json, credentials) credentials.truncate() except decoder.JSONDecodeError: write_error("credentials.json does not contain a valid json") reset_command() exit()
def update_gtk_rs_blog(args, temp_dir): if args.doc_only is True or args.tags_only is True: return write_msg('=> Updating blog...') if update_badges(consts.BLOG_REPO, temp_dir, args.specified_crate) is False: write_error("Error when trying to update badges...") elif args.no_push is False: commit_and_push(consts.BLOG_REPO, temp_dir, "Update versions", consts.MASTER_TMP_BRANCH) create_pull_request(consts.BLOG_REPO, consts.MASTER_TMP_BRANCH, "master", args.token) write_msg('Done!')
def generate_new_tag(repository, temp_dir, specified_crate): versions = {} version = None # In some repositories (like sys), there are more than one crates. In such case, we try to # get the most common version number and then we create the tag from there. # # First, we get all versions. for crate in consts.CRATE_LIST: if crate['repository'] == repository: versions[crate['crate']] = CRATES_VERSION[crate['crate']] if crate['crate'].endswith('-sys') or crate['crate'].endswith( '-sys-rs'): version = CRATES_VERSION[crate['crate']] if (specified_crate is not None and (specified_crate.endswith('-sys') or specified_crate.endswith('-sys-rs'))): write_msg( 'Seems like "{}" is part of a repository with multiple crates so no \ tag generation this time...'.format(specified_crate)) return if version is None: most_common = {} # Now we get how many crates have this version. for version in versions: if versions[version] in most_common: most_common[versions[version]] += 1 else: most_common[versions[version]] = 1 # Now we get the "lowest" version that will be used as default tag name. for common in most_common: if version is None or compare_versions(common, version) < 0: version = common # And now we get the most common tag name. for common in most_common: if version is None or most_common[version] < most_common[common]: version = common if version is None: write_error( 'Something impossible happened for "{}": no version can be tagged...' .format(repository)) input( 'If you think you can do better, go ahead! (In "{}") Then press ENTER to continue' .format(join(temp_dir, repository))) return write_msg('==> Creating new tag "{}" for repository "{}"...'.format( version, repository)) create_tag_and_push(version, repository, temp_dir)
def update_version(version, update_type, section_name, place_type="section"): version_split = version.replace('"', '').split('.') if len(version_split) != 3: # houston, we've got a problem! write_error('Invalid version in {} "{}": {}'.format( place_type, section_name, version)) return None if update_type == UpdateType.MINOR: version_split[update_type] = str(int(version_split[update_type]) + 1) elif update_type == UpdateType.MEDIUM: version_split[update_type] = str(int(version_split[update_type]) + 1) version_split[UpdateType.MINOR] = '0' else: version_split[update_type] = str(int(version_split[update_type]) + 1) version_split[UpdateType.MEDIUM] = '0' version_split[UpdateType.MINOR] = '0' return '"{}"'.format('.'.join(version_split))
def write_command(user): if "-m" in sys.argv: try: ws = get_worksheet() current_row = next_available_row(ws) display_loading_message("Saving message", "Message saved") message = get_argument(sys.argv, "-m") set_name_date(current_row, user, ws) ws.update_acell("C{}".format(current_row), message) if "-t" in sys.argv: description = get_argument(sys.argv, "-t") ws.update_acell("D{}".format(current_row), description) hide_loading_message_with_error(False) except Exception: hide_loading_message_with_error(True) else: write_error("A message argument should be specified")
def end_docs_build(temp_dir): path = join(temp_dir, consts.DOC_REPO) revert_changes(consts.DOC_REPO, temp_dir, ['COPYRIGHT.txt', 'LICENSE-APACHE.txt', 'LICENSE-MIT.txt']) try: with open(join(path, 'search-index.js'), 'w') as file: file.write('\n'.join(SEARCH_INDEX_BEFORE) + '\n') if SEARCH_INDEX[-1].endswith("},\\"): SEARCH_INDEX[-1] = SEARCH_INDEX[ -1][:-2] + '\\' # we remove the last comma file.write('\n'.join(SEARCH_INDEX)) file.write('\n'.join(SEARCH_INDEX_AFTER)) add_to_commit(consts.DOC_REPO, temp_dir, ['.']) except Exception as err: write_error('An exception occured in "end_docs_build": {}'.format(err)) input("Press ENTER to continue...") input( 'If you want to prevent "{}" to be updated, now is the good time! Press ENTER to ' 'continue...'.format(join(path, "main.js")))
def clone_repositories(args, temp_dir): write_msg('=> Cloning the repositories...') repositories = [] for crate in args.crates: crate = crate['crate'] if args.specified_crate is not None and crate[ 'crate'] != args.specified_crate: continue if crate["repository"] not in repositories: repositories.append(crate["repository"]) if clone_repo(crate["repository"], temp_dir) is False: write_error('Cannot clone the "{}" repository...'.format( crate["repository"])) return [] if len(repositories) < 1: write_msg('No crate "{}" found. Aborting...'.format( args.specified_crate)) return [] if args.doc_only is False: if clone_repo(consts.BLOG_REPO, temp_dir, depth=1) is False: write_error('Cannot clone the "{}" repository...'.format( consts.BLOG_REPO)) return [] if clone_repo(consts.DOC_REPO, temp_dir, depth=1) is False: write_error('Cannot clone the "{}" repository...'.format( consts.DOC_REPO)) return [] write_msg('Done!') return repositories
def main(argv): try: opts, args = getopt.getopt(argv, "ht:m:c:", [ "help", "token=", "mode=", "no-push", "doc-only", "crate", "badges-only" ]) except getopt.GetoptError: write_help() sys.exit(2) token = None mode = None no_push = False doc_only = False specified_crate = None badges_only = False for opt, arg in opts: if opt in ('-h', '--help'): write_help() sys.exit(0) elif opt in ("-t", "--token"): token = arg elif opt in ("-m", "--mode"): mode = UpdateType.create_from_string(arg) if mode is None: write_error( '{}: Invalid update type received. Accepted values: ' '(MINOR|MEDIUM|MAJOR)'.format(opt)) sys.exit(3) elif opt in ("--no-push"): no_push = True elif opt in ("--doc-only"): doc_only = True elif opt in ("--badges-only"): badges_only = True elif opt in ('-c', '--crate'): specified_crate = arg else: write_msg('"{}": unknown option'.format(opt)) write_msg('Use "-h" or "--help" to see help') sys.exit(0) if token is None and no_push is False: write_error('Missing token argument.') sys.exit(4) if mode is None and doc_only is False and badges_only is False: write_error('Missing update type argument.') sys.exit(5) start(mode, token, no_push, doc_only, specified_crate, badges_only)
def start(update_type, token, no_push, doc_only, specified_crate, badges_only): write_msg('=> Creating temporary directory...') with TemporaryDirectory() as temp_dir: write_msg('Temporary directory created in "{}"'.format(temp_dir)) write_msg('=> Cloning the repositories...') repositories = [] for crate in consts.CRATE_LIST: if specified_crate is not None and crate[ 'crate'] != specified_crate: continue if crate["repository"] not in repositories: repositories.append(crate["repository"]) if clone_repo(crate["repository"], temp_dir) is False: write_error('Cannot clone the "{}" repository...'.format( crate["repository"])) return if len(repositories) < 1: write_msg( 'No crate "{}" found. Aborting...'.format(specified_crate)) return if doc_only is False: if clone_repo(consts.BLOG_REPO, temp_dir, depth=1) is False: write_error('Cannot clone the "{}" repository...'.format( consts.BLOG_REPO)) return if clone_repo(consts.DOC_REPO, temp_dir, depth=1) is False: write_error('Cannot clone the "{}" repository...'.format( consts.DOC_REPO)) return write_msg('Done!') if doc_only is False: write_msg('=> Updating [master] crates version...') for crate in consts.CRATE_LIST: if specified_crate is not None and crate[ 'crate'] != specified_crate: continue if update_repo_version(crate["repository"], crate["crate"], crate["path"], temp_dir, update_type, badges_only) is False: write_error( 'The update for the "{}" crate failed...'.format( crate["crate"])) return write_msg('Done!') if badges_only is False: write_msg('=> Committing{} to the "{}" branch...'.format( " and pushing" if no_push is False else "", consts.MASTER_TMP_BRANCH)) for repo in repositories: commit(repo, temp_dir, "Update versions [ci skip]") if no_push is False: push(repo, temp_dir, consts.MASTER_TMP_BRANCH) write_msg('Done!') if no_push is False: write_msg('=> Creating PRs on master branch...') for repo in repositories: create_pull_request(repo, consts.MASTER_TMP_BRANCH, "master", token) write_msg('Done!') write_msg('=> Building blog post...') build_blog_post(repositories, temp_dir, token) write_msg('Done!') write_msg('=> Checking out "crate" branches') for repo in repositories: checkout_target_branch(repo, temp_dir, "crate") write_msg('Done!') if doc_only is False and badges_only is False: write_msg('=> Merging "master" branches into "crate" branches...') for repo in repositories: merging_branches(repo, temp_dir, "master") write_msg('Done!') write_msg('=> Updating [crate] crates version...') for crate in consts.CRATE_LIST: if specified_crate is not None and crate[ 'crate'] != specified_crate: continue if update_crate_version(crate["repository"], crate["crate"], crate["path"], temp_dir, specified_crate) is False: write_error( 'The update for the "{}" crate failed...'.format( crate["crate"])) return write_msg('Done!') write_msg('=> Committing{} to the "{}" branch...'.format( " and pushing" if no_push is False else "", consts.CRATE_TMP_BRANCH)) for repo in repositories: commit(repo, temp_dir, "Update versions [ci skip]") if no_push is False: push(repo, temp_dir, consts.CRATE_TMP_BRANCH) write_msg('Done!') if no_push is False: write_msg('=> Creating PRs on crate branch...') for repo in repositories: create_pull_request(repo, consts.CRATE_TMP_BRANCH, "crate", token) write_msg('Done!') write_msg('+++++++++++++++') write_msg('++ IMPORTANT ++') write_msg('+++++++++++++++') write_msg( 'Almost everything has been done. Take a deep breath, check for opened ' 'pull requests and once done, we can move forward!') write_msg("\n{}\n".format('\n'.join(PULL_REQUESTS))) PULL_REQUESTS.append('=============') input('Press ENTER to continue...') write_msg('=> Publishing crates...') for crate in consts.CRATE_LIST: if specified_crate is not None and crate[ 'crate'] != specified_crate: continue publish_crate(crate["repository"], crate["path"], temp_dir, crate['crate']) write_msg('Done!') write_msg('=> Creating PR for examples repository') create_pull_request("examples", "pending", "master", token) write_msg('Done!') write_msg("=> Generating tags...") for repo in repositories: generate_new_tag(repo, temp_dir, specified_crate) write_msg('Done!') if badges_only is False: write_msg( '=> Preparing doc repo (too much dark magic in here urg)...') cleanup_doc_repo(temp_dir) write_msg('Done!') write_msg('=> Building docs...') for repo in repositories: if repo != "sys": # Maybe we should generate docs for sys crates as well? write_msg('-> Building docs for {}...'.format(repo)) build_docs(repo, temp_dir) end_docs_build(temp_dir) write_msg('Done!') write_msg('=> Committing{} docs to the "{}" branch...'.format( " and pushing" if no_push is False else "", consts.CRATE_TMP_BRANCH)) commit(consts.DOC_REPO, temp_dir, "Regen docs") if no_push is False: push(consts.DOC_REPO, temp_dir, consts.CRATE_TMP_BRANCH) create_pull_request(consts.DOC_REPO, consts.CRATE_TMP_BRANCH, "gh-pages", token) write_msg("New pull request(s):\n\n{}\n".format( '\n'.join(PULL_REQUESTS))) write_msg('Done!') if doc_only is False: write_msg('=> Updating blog...') if update_badges(consts.BLOG_REPO, temp_dir, specified_crate) is False: write_error("Error when trying to update badges...") elif no_push is False: commit_and_push(consts.BLOG_REPO, temp_dir, "Update versions", consts.MASTER_TMP_BRANCH) create_pull_request(consts.BLOG_REPO, consts.MASTER_TMP_BRANCH, "master", token) write_msg('Done!') write_msg('Seems like most things are done! Now remains:') write_msg( " * Check generated docs for all crates (don't forget to enable features!)." ) input( 'Press ENTER to leave (once done, the temporary directory "{}" will be destroyed)' .format(temp_dir))
def build_blog_post(repositories, temp_dir, token): content = '''--- layout: post author: {} title: {} categories: [front, crates] date: {} --- * Write intro here * ### Changes For the interested ones, here is the list of the (major) changes: '''.format(input('Enter author name: '), input('Enter title: '), time.strftime("%Y-%m-%d %H:00:00 +0000")) contributors = [] git = Github(token) oldest_date = None for repo in repositories: checkout_target_branch(repo, temp_dir, "crate") success, out, err = get_last_commit_date(repo, temp_dir) if not success: write_msg("Couldn't get PRs for '{}': {}".format(repo, err)) continue max_date = datetime.date.fromtimestamp(int(out)) if oldest_date is None or max_date < oldest_date: oldest_date = max_date write_msg("Gettings merged PRs from {}...".format(repo)) merged_prs = git.get_pulls(repo, consts.ORGANIZATION, 'closed', max_date, only_merged=True) write_msg("=> Got {} merged PRs".format(len(merged_prs))) if len(merged_prs) < 1: continue repo_url = '{}/{}/{}'.format(consts.GITHUB_URL, consts.ORGANIZATION, repo) content += '[{}]({}):\n\n'.format(repo, repo_url) content += write_merged_prs(merged_prs, contributors, repo_url) write_msg("Gettings merged PRs from gir...") merged_prs = git.get_pulls('gir', consts.ORGANIZATION, 'closed', oldest_date, only_merged=True) write_msg("=> Got {} merged PRs".format(len(merged_prs))) if len(merged_prs) > 0: repo_url = '{}/{}/{}'.format(consts.GITHUB_URL, consts.ORGANIZATION, 'gir') content += ( 'All this was possible thanks to the [gtk-rs/gir]({}) project as well:\n\n' .format(repo_url)) content += write_merged_prs(merged_prs, contributors, repo_url) content += 'Thanks to all of our contributors for their (awesome!) work for this release:\n\n' content += '\n'.join([ ' * [@{}]({}/{})'.format(contributor, consts.GITHUB_URL, contributor) for contributor in contributors ]) content += '\n' file_name = join( join(temp_dir, consts.BLOG_REPO), '_posts/{}-new-release.md'.format(time.strftime("%Y-%m-%d"))) try: with open(file_name, 'w') as outfile: outfile.write(content) write_msg('New blog post written into "{}".'.format(file_name)) add_to_commit(consts.BLOG_REPO, temp_dir, [file_name]) commit(consts.BLOG_REPO, temp_dir, "Add new blog post") except Exception as e: write_error('build_blog_post failed: {}'.format(e)) write_msg( '\n=> Here is the blog post content:\n{}\n<='.format(content))
def apply_config(self): utils.log("Applying settings to {}".format(utils.CONFIG_PATH)) config = OrderedDict() overclock_preset = utils.get_setting('overclock_preset') utils.log("Using {} overclock settings".format(overclock_preset)) if overclock_preset == 'Custom': for prop in utils.OVERCLOCK_PRESET_PROPERTIES: config[prop] = utils.get_property_setting(prop) elif overclock_preset in utils.OVERCLOCK_PRESETS: config = OrderedDict( zip(utils.OVERCLOCK_PRESET_PROPERTIES, utils.OVERCLOCK_PRESETS[overclock_preset])) for prop in utils.OTHER_PROPERTIES: value = utils.get_property_setting(prop) if value is not None: config[prop] = value if ('force_turbo' in config and config['force_turbo'] == 1 and 'over_voltage' in config and config['over_voltage'] > 0): if not xbmcgui.Dialog().yesno( "OpenELEC RPi Config WARNING!!", "Overvolting with dynamic overclock disabled", "will void your warranty!!", "Continue, or fix by enabling dynamic overclock?", "Fix", "Continue"): utils.log("Enabling dynamic overclock") config['force_turbo'] = 0 else: utils.log("Warranty warning was ignored") if 'max_usb_current' in config and config['max_usb_current'] == 1: if not xbmcgui.Dialog().yesno( "OpenELEC RPi Config WARNING!", "To output 1.2A from the USB ports", "you will need to use a good 2A power supply.", "Are you sure you want to set max_usb_current?"): config['max_usb_current'] = 0 updated = False if os.path.isfile(utils.CONFIG_PATH): with open(utils.CONFIG_PATH, 'r') as f: config_txt = f.read() config_txt_new = config_txt for prop, value in config.iteritems(): utils.log("==== {} ====".format(prop)) config_property_re = re.compile( utils.CONFIG_SUB_RE_STR.format(prop), re.MULTILINE) match = config_property_re.search(config_txt) if match: comment = bool(match.group(1)) old_value = match.group(3) if value is None: utils.log(" Commenting out") config_txt_new = config_property_re.sub( utils.comment_out, config_txt_new) updated = True elif comment or str(value) != old_value: utils.log(" Setting to {}".format(value)) config_txt_new = config_property_re.sub( partial(utils.replace_value, value), config_txt_new) updated = True else: utils.log(" Unchanged ({})".format(value)) elif value is not None: utils.log(" Appending {}={}".format(prop, value)) config_txt_new += utils.property_value_str(prop, value) + '\n' updated = True else: utils.log("A new {} will be created".format(utils.CONFIG_PATH)) config_txt_new = utils.add_property_values(config) updated = True reboot_needed = False if updated: reboot_needed = True with utils.remount(): try: utils.write_config(config_txt_new) except (OSError, IOError) as e: reboot_needed = False utils.write_error(utils.CONFIG_PATH, str(e)) if reboot_needed: if utils.restart_countdown( "Ready to reboot to apply changes in config.txt"): xbmc.restart() else: utils.log("Cancelled reboot") else: utils.log("No changes made")
def init_app(): print("Starting servy init process") print("............................") credentials_path = get_credentials_path() while True: default_spreadsheet = input("Insert the spreadsheets name\n") if default_spreadsheet: try: append_default_spreadsheet(credentials_path, default_spreadsheet) break except FileNotFoundError: write_error("\n'credentials.json' does not exists\n") print("Enter/Paste the downloaded content. Ctrl-D to save it.") try: credentials_content = [] while True: try: line = input() except EOFError: break credentials_content.append(line) with open(credentials_path, "w+") as f: for line in credentials_content: f.write(line + "\n") append_default_spreadsheet(credentials_path, default_spreadsheet) break except PermissionError: write_error("Permission error\n`servy init` should be run using root permissions\n") exit() except Exception as e: write_error("An error occured while saving credentials\n") exit() ss = get_spreadsheet() if ss and ss.sheet1: resume_ss = input( "A spreadsheet with this name already exists. Do you want to use it? Y/N\n") if resume_ss == "Y": print("Spreadsheet in use: " + default_spreadsheet) print("The following users has read permission to this file") print_permissions(ss) return print("Insert the email you want to have access to the spreadsheet") while True: email = input("Insert email: ") if email: if not validate_email(email): write_error("Invalid email") else: break display_loading_message("Creating spreadsheet " + default_spreadsheet, "Created spreadsheet " + default_spreadsheet) try: if ss: delete_spreadsheet(ss) ws = create_spreadsheet(email) init_spreadsheet(ws) hide_loading_message_with_error(False) except: hide_loading_message_with_error(True)
def apply_config(self): utils.log("Applying settings to {}".format(utils.CONFIG_PATH)) config = OrderedDict() overclock_preset = utils.get_setting('overclock_preset') utils.log("Using {} overclock settings".format(overclock_preset)) if overclock_preset == 'Custom': for prop in utils.OVERCLOCK_PRESET_PROPERTIES: config[prop] = utils.get_property_setting(prop) elif overclock_preset in utils.OVERCLOCK_PRESETS: config = OrderedDict(zip(utils.OVERCLOCK_PRESET_PROPERTIES, utils.OVERCLOCK_PRESETS[overclock_preset])) for prop in utils.OTHER_PROPERTIES: value = utils.get_property_setting(prop) if value is not None: config[prop] = value if ('force_turbo' in config and config['force_turbo'] == 1 and 'over_voltage' in config and config['over_voltage'] > 0): if not xbmcgui.Dialog().yesno("OpenELEC RPi Config WARNING!!", "Overvolting with dynamic overclock disabled", "will void your warranty!!", "Continue, or fix by enabling dynamic overclock?", "Fix", "Continue"): utils.log("Enabling dynamic overclock") config['force_turbo'] = 0 else: utils.log("Warranty warning was ignored") if 'max_usb_current' in config and config['max_usb_current'] == 1: if not xbmcgui.Dialog().yesno("OpenELEC RPi Config WARNING!", "To output 1.2A from the USB ports", "you will need to use a good 2A power supply.", "Are you sure you want to set max_usb_current?"): config['max_usb_current'] = 0 updated = False if os.path.isfile(utils.CONFIG_PATH): with open(utils.CONFIG_PATH, 'r') as f: config_txt = f.read() config_txt_new = config_txt for prop, value in config.iteritems(): utils.log("==== {} ====".format(prop)) config_property_re = re.compile(utils.CONFIG_SUB_RE_STR.format(prop), re.MULTILINE) match = config_property_re.search(config_txt) if match: comment = bool(match.group(1)) old_value = match.group(3) if value is None: utils.log(" Commenting out") config_txt_new = config_property_re.sub(utils.comment_out, config_txt_new) updated = True elif comment or str(value) != old_value: utils.log(" Setting to {}".format(value)) config_txt_new = config_property_re.sub(partial(utils.replace_value, value), config_txt_new) updated = True else: utils.log(" Unchanged ({})".format(value)) elif value is not None: utils.log(" Appending {}={}".format(prop, value)) config_txt_new += utils.property_value_str(prop, value) + '\n' updated = True else: utils.log("A new {} will be created".format(utils.CONFIG_PATH)) config_txt_new = utils.add_property_values(config) updated = True reboot_needed = False if updated: reboot_needed = True with utils.remount(): try: utils.write_config(config_txt_new) except (OSError, IOError) as e: reboot_needed = False utils.write_error(utils.CONFIG_PATH, str(e)) if reboot_needed: if utils.restart_countdown("Ready to reboot to apply changes in config.txt"): xbmc.restart() else: utils.log("Cancelled reboot") else: utils.log("No changes made")
def try_init(message): write_error(message) if input("Do you want to init the app now? Y/N \n") == "Y": init_app() else: exit()
def parse_arguments(argv): # pylint: disable=too-many-branches,too-many-return-statements try: opts = getopt.getopt(argv, "ht:m:c:", ["help", "token=", "mode=", "no-push", "doc-only", "crate", "badges-only", "tags-only", "pick-update-type-for-crates", "pick-crates", "blog-only"])[0] # second argument is "args" except getopt.GetoptError: write_help() return None instance = Arguments() pick_update_type_for_crates = False for opt, arg in opts: if opt in ('-h', '--help'): write_help() return None if opt in ("-t", "--token"): instance.token = arg elif opt in ("-m", "--mode"): instance.mode = UpdateType.create_from_string(arg) if instance.mode is None: write_error('{}: Invalid update type received. Accepted values: ' '(MINOR|MEDIUM|MAJOR)'.format(opt)) return None elif opt == "--no-push": instance.no_push = True elif opt == "--doc-only": instance.doc_only = True elif opt == "--badges-only": instance.badges_only = True elif opt in ('-c', '--crate'): instance.specified_crate = arg elif opt == '--tags-only': instance.tags_only = True elif opt == '--blog-only': instance.blog_only = True elif opt == '--pick-crates': instance.crates = [] elif opt == '--pick-update-type-for-crates': pick_update_type_for_crates = True else: write_msg('"{}": unknown option'.format(opt)) write_msg('Use "-h" or "--help" to see help') return None if instance.token is None and instance.no_push is False and instance.blog_only is False: # In this case, I guess it's not an issue to not have a github token... write_error('Missing token argument.') return None # To make pylint happy. only_checks = (instance.doc_only is False or instance.badges_only is False or instance.tags_only is False or instance.blog_only is False) if (instance.mode is None and only_checks is False and pick_update_type_for_crates is False): write_error('Missing update type argument.') return None default_updates = {"sys": None, "non-sys": None} if len(instance.crates) == 0: for crate in consts.CRATE_LIST: if get_answer('Do you want to include "{}" in this release?') is True: instance.crates.append( { 'up-type': get_up_type(crate['crate'], instance.mode, pick_update_type_for_crates, default_updates), 'crate': crate, }) if ask_updates_confirmation(instance.crates) is False: write_msg('OK! Aborting then!') return None else: instance.crates = [ { 'up-type': get_up_type(crate['crate'], instance.mode, pick_update_type_for_crates, default_updates), 'crate': crate, } for crate in instance.crates] if (pick_update_type_for_crates is True and ask_updates_confirmation(instance.crates) is False): write_msg('OK! Aborting then!') return None return instance
def build_docs(repo_name, temp_dir, extra_path, crate_name): # pylint: disable=too-many-locals path = join(join(temp_dir, repo_name), extra_path) features = get_features(join(path, 'Cargo.toml')) # We can't add "--no-deps" argument to cargo doc, otherwise we lose links to items of # other crates... # # Also, we run "cargo update" in case the lgpl-docs repository has been updated (so we get the # last version). command = [ 'bash', '-c', ('cd {} && cargo update && cargo rustdoc --no-default-features ' '--features "{}"').format(path, features) ] if not exec_command_and_print_error(command): input( "Couldn't generate docs! Try to fix it and then press ENTER to continue..." ) doc_folder = join(path, 'target/doc') try: file_list = ' '.join([ '"{}"'.format(f) for f in listdir(doc_folder) if isfile(join(doc_folder, f)) ]) except Exception as err: write_error('Error occured in build docs: {}'.format(err)) input( "It seems like the \"{}\" folder doesn't exist. Try to fix it then press ENTER..." .format(doc_folder)) # Copy documentation files command = [ 'bash', '-c', 'cd {} && cp -r "{}" {} "{}"'.format(doc_folder, crate_name.replace('-', '_'), file_list, join(temp_dir, consts.DOC_REPO)) ] if not exec_command_and_print_error(command): input( "Couldn't copy docs! Try to fix it and then press ENTER to continue..." ) # Copy source files destination = "{}/src".format(join(temp_dir, consts.DOC_REPO)) command = [ 'bash', '-c', 'cd {0} && mkdir -p "{1}" && cp -r "src/{2}" "{1}/"'.format( doc_folder, destination, crate_name.replace('-', '_')) ] if not exec_command_and_print_error(command): input( "Couldn't copy doc source files! Try to fix it and then press ENTER to continue..." ) search_index = join(path, 'target/doc/search-index.js') lines = get_file_content(search_index).split('\n') before = True fill_extras = len(SEARCH_INDEX_BEFORE) == 0 found = False for line in lines: if line.startswith('"'): before = False # We need to be careful in here if we're in a sys repository (which should never be the # case!). if line.startswith('"{}":'.format(crate_name.replace('-', '_'))): if line.endswith('}\\'): line = line[:-1] + ',\\' SEARCH_INDEX.append(line) found = True elif fill_extras is True: if before is True: SEARCH_INDEX_BEFORE.append(line) else: SEARCH_INDEX_AFTER.append(line) if found is False: input( "Couldn't find \"{}\" in `{}`!\nTry to fix it and then press ENTER to continue..." .format(crate_name.replace('-', '_'), search_index))