Skip to content

Instantly share code, notes, and snippets.

@kchodorow
Last active February 5, 2016 21:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kchodorow/450c6e0ab3eeab57e9d8 to your computer and use it in GitHub Desktop.
Save kchodorow/450c6e0ab3eeab57e9d8 to your computer and use it in GitHub Desktop.
Replaces illegal repository names with legal ones.
#!/usr/bin/env python
#
# Copyright 2016 The Bazel Authors. All arights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Converts WORKSPACE and BUILD files to use new workspace name format.
# Run this in the directory containing your project's WORKSPACE file.
import difflib
import os
import os.path
import re
import sys
QUOTE_PATTERN = re.compile('["\']')
VALID_WORKSPACE_PATTERN = re.compile('^[A-Za-z][\w]*$')
def confirmed(confirm):
return confirm != "n" and confirm != "N"
def replace_in_files(this_dir, old_name, new_name):
for filename in os.listdir(this_dir):
full_path = "%s/%s" % (this_dir, filename)
if filename == 'BUILD':
handle_build_file(full_path, old_name, new_name)
else:
handle_non_build(full_path, old_name, new_name)
def handle_non_build(full_path, old_name, new_name):
if os.path.isdir(full_path) \
and not os.path.basename(full_path).startswith("bazel-") \
and not os.path.basename(full_path).startswith("."):
replace_in_files(full_path, old_name, new_name)
def handle_build_file(full_path, old_name, new_name):
old_repo_name = "@%s" % old_name
new_repo_name = "@%s" % new_name
old_build_file = full_path
new_build_file = "%s.new" % full_path
if old_repo_name not in open(old_build_file).read():
return
with open(new_build_file, "wt") as fout:
with open(old_build_file, "rt") as fin:
for line in fin:
fout.write(line.replace(old_repo_name, new_repo_name))
fromlines = open(old_build_file, 'U').readlines()
tolines = open(new_build_file, 'U').readlines()
diff = difflib.unified_diff(
fromlines, tolines, old_build_file, new_build_file)
sys.stdout.writelines(diff)
confirm = raw_input("Does this change look okay? [Y/n] ")
if confirmed(confirm):
os.rename(new_build_file, old_build_file)
else:
print "Leaving BUILD file unmodified (changes in %s)" % new_build_file
class WorkspaceFile:
def __init__(self):
self.line_no_ = 0
self.found_errors_ = False
def check(self):
with open('WORKSPACE.new', 'wt') as new_workspace:
with open('WORKSPACE', 'r') as old_workspace:
for old_line in old_workspace:
self.line_no_ = self.line_no_ + 1
line = self.process_line_(old_line)
new_workspace.write(line)
if self.found_errors_:
os.rename('WORKSPACE.new', 'WORKSPACE')
print "Done, exiting."
else:
os.remove('WORKSPACE.new')
print "WORKSPACE looks good!"
def process_line_(self, old_line):
if "name = " not in old_line:
return old_line
old_name = WorkspaceFile.extract_name_(old_line)
if VALID_WORKSPACE_PATTERN.match(old_name):
return old_line
self.found_errors_ = True
new_name = re.sub('[\W]', '_', old_name)
replace = raw_input(
"Illegal rule name at line %d: '%s', replace with '%s'? [Y/n] " %
(self.line_no_, old_name, new_name))
if replace is "n":
return old_line
new_line = WorkspaceFile.insert_name_(old_line, new_name)
replace_in_files(os.getcwd(), old_name, new_name)
return new_line
@staticmethod
def extract_name_(line):
quote = QUOTE_PATTERN.search(line)
if quote is None:
raise Exception("Could not find a name in %s" % line)
quote_index = quote.start()
return line[quote_index + 1:QUOTE_PATTERN.search(line, quote_index + 1)
.start()]
@staticmethod
def insert_name_(line, name):
quote_index = QUOTE_PATTERN.search(line).start()
return line[0:quote_index + 1] + name \
+ line[QUOTE_PATTERN.search(line, quote_index + 1).start():]
if not os.path.isfile('WORKSPACE'):
print "Run from a directory containing a WORKSPACE file."
exit()
print(
"This tool will read your WORKSPACE file, find any repositories with\n"
"illegal characters in the names, and suggest a replacement name. It will\n"
"then attempt to replace all other references to these repositories in your\n"
"codebase (prompting you before each change).\n\n"
"This tool is provided with NO GUARANTEE and might do absolutely\n"
"anything. It is highly recommended that you backup your files before\n"
"running this.\n")
confirm = raw_input("That said, shall we begin? [Y/n] ")
print("")
if not confirmed(confirm):
print "\nBye."
exit()
if os.path.isfile('WORKSPACE.new'):
print "This script uses WORKSPACE.new as a temp file, but one already exists"
print "in the cwd."
exit()
workspace_file = WorkspaceFile()
workspace_file.check()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment