hosts/updateHostsFile.py

551 lines
21 KiB
Python
Raw Normal View History

2015-10-26 23:46:48 +01:00
#!/usr/bin/env python
# Script by Ben Limmer
# https://github.com/l1m5
#
# This Python script will combine all the host files you provide
# as sources into one, unique host file to keep you internet browsing happy.
2016-02-08 02:09:42 +01:00
# pylint: disable=invalid-name
# pylint: disable=bad-whitespace
2015-10-26 23:46:48 +01:00
# Making Python 2 compatible with Python 3
from __future__ import absolute_import, division, print_function, unicode_literals
import os
import platform
import re
import shutil
import string
import subprocess
import sys
import tempfile
import time
2015-11-05 13:38:08 +01:00
import glob
import argparse
import socket
import json
2016-03-24 04:36:47 +01:00
2015-10-26 23:16:55 +01:00
# zip files are not used actually, support deleted
# StringIO is not needed in Python 3
# Python 3 works differently with urlopen
2015-10-26 23:46:48 +01:00
# Supporting urlopen in Python 2 and Python 3
try:
2016-02-08 01:15:05 +01:00
from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError
2015-10-26 23:46:48 +01:00
except ImportError:
2016-02-08 01:15:05 +01:00
from urlparse import urlparse
from urllib import urlencode
from urllib2 import urlopen, Request, HTTPError
2015-10-26 23:46:48 +01:00
2016-03-24 04:36:47 +01:00
# Detecting Python 3 for version-dependent implementations
Python3 = sys.version_info >= (3,0)
2015-10-26 23:46:48 +01:00
# This function handles both Python 2 and Python 3
def getFileByUrl(url):
2016-02-08 01:15:05 +01:00
try:
f = urlopen(url)
return f.read().decode("UTF-8")
2016-02-08 01:15:05 +01:00
except:
2016-02-08 01:28:31 +01:00
print ("Problem getting file: ", url)
2016-02-08 01:15:05 +01:00
# raise
2015-10-26 23:46:48 +01:00
2015-10-26 23:16:55 +01:00
# In Python 3 "print" is a function, braces are added everywhere
2015-10-26 23:46:48 +01:00
# This function works in both Python 2 and Python 3
def myInput(msg = ""):
2016-02-08 01:15:05 +01:00
if Python3:
2016-02-08 01:28:31 +01:00
return input(msg)
2016-02-08 01:15:05 +01:00
else:
2016-02-08 01:28:31 +01:00
return raw_input(msg)
2015-10-26 23:46:48 +01:00
# Cross-python writing function
def writeData(f, data):
2016-02-08 01:15:05 +01:00
if Python3:
f.write(bytes(data, 'UTF-8'))
2016-02-08 01:15:05 +01:00
else:
f.write(str(data).encode('UTF-8'))
2015-10-29 00:33:16 +01:00
2015-11-05 13:38:08 +01:00
# This function doesn't list hidden files
def listdir_nohidden(path):
return glob.glob(os.path.join(path, '*'))
2015-10-26 23:46:48 +01:00
# Project Settings
BASEDIR_PATH = os.path.dirname(os.path.realpath(__file__))
2016-03-24 06:10:13 +01:00
defaults = {
"numberofrules" : 0,
"datapath" : os.path.join(BASEDIR_PATH, "data"),
"freshen" : True,
"replace" : False,
"extensionspath" : os.path.join(BASEDIR_PATH, "extensions"),
"extensions" : [],
"outputsubfolder" : "",
"datafilenames" : "hosts",
"targetip" : "0.0.0.0",
"updateurlfilename" : "update.info",
"readmefilename" : "readme.md",
"readmetemplate" : os.path.join(BASEDIR_PATH, "readme_template.md"),
"readmedata" : {},
"readmedatafilename" : "readmeData.json",
"exclusionpattern" : "([a-zA-Z\d-]+\.){0,}",
"exclusionregexs" : [],
"exclusions" : [],
"commonexclusions" : ["hulu.com"],
"whitelistfile" : os.path.join(BASEDIR_PATH, "whitelist")}
options = {}
settings = {}
def main():
2016-02-28 02:16:41 +01:00
parser = argparse.ArgumentParser(description="Creates a unified hosts file from hosts stored in data subfolders.")
parser.add_argument("--auto", "-a", dest="auto", default=False, action='store_true', help="Run without prompting.")
parser.add_argument("--replace", "-r", dest="replace", default=False, action='store_true', help="Replace your active hosts file with this new hosts file.")
2016-03-24 06:10:13 +01:00
parser.add_argument("--ip", "-i", dest="targetip", default="0.0.0.0", help="Target IP address. Default is 0.0.0.0.")
parser.add_argument("--extensions", "-e", dest="extensions", default=[], nargs='*', help="Host extensions to include in the final hosts file.")
2016-03-24 06:10:13 +01:00
parser.add_argument("--output", "-o", dest="outputsubfolder", default="", help="Output subfolder for generated hosts file.")
parser.add_argument("--noupdate", "-n", dest="noupdate", default=False, action='store_true', help="Don't update from host data sources.")
global defaults, options, settings
options = vars(parser.parse_args())
2016-03-24 06:10:13 +01:00
options["outputpath"] = os.path.join(BASEDIR_PATH, options["outputsubfolder"])
options["freshen"] = not options["noupdate"]
settings = {}
settings.update(defaults)
settings.update(options)
settings["sources"] = listdir_nohidden(settings["datapath"])
# All our extensions folders...
2016-03-24 06:10:13 +01:00
settings["extensions"] = [os.path.basename(item) for item in listdir_nohidden(settings["extensionspath"])]
# ... intersected with the extensions passed-in as arguments, then sorted.
2016-03-24 06:10:13 +01:00
settings["extensions"] = sorted( list(set(options["extensions"]).intersection(settings["extensions"])) )
2016-03-24 06:10:13 +01:00
with open(settings["readmedatafilename"], 'r') as f:
settings["readmedata"] = json.load(f)
2016-02-08 01:15:05 +01:00
promptForUpdate()
promptForExclusions()
mergeFile = createInitialFile()
removeOldHostsFile()
finalFile = removeDupsAndExcl(mergeFile)
finalizeFile(finalFile)
2016-03-24 06:10:13 +01:00
updateReadmeData()
printSuccess('Success! The hosts file has been saved in folder ' + settings["outputsubfolder"] + '\nIt contains ' +
"{:,}".format(settings["numberofrules"]) + ' unique entries.')
promptForMove(finalFile)
# Prompt the User
def promptForUpdate():
2016-02-08 01:15:05 +01:00
# Create hosts file if it doesn't exists
if not os.path.isfile(os.path.join(BASEDIR_PATH, 'hosts')):
2016-02-08 01:15:05 +01:00
try:
open(os.path.join(BASEDIR_PATH, 'hosts'), 'w+').close()
2016-02-08 01:15:05 +01:00
except:
printFailure("ERROR: No 'hosts' file in the folder, try creating one manually")
2016-02-08 01:15:05 +01:00
2016-03-24 06:10:13 +01:00
if not settings["freshen"]:
return
2016-03-24 06:10:13 +01:00
response = "yes" if settings["auto"] else query_yes_no("Do you want to update all data sources?")
if response == "yes":
2016-02-08 01:15:05 +01:00
updateAllSources()
else:
2016-03-24 06:10:13 +01:00
if not settings["auto"]:
print ("OK, we\'ll stick with what we\'ve got locally.")
def promptForExclusions():
2016-03-24 06:10:13 +01:00
response = "no" if settings["auto"] else query_yes_no("Do you want to exclude any domains?\n" +
2016-02-08 01:15:05 +01:00
"For example, hulu.com video streaming must be able to access " +
"its tracking and ad servers in order to play video.")
2016-02-08 01:23:40 +01:00
if response == "yes":
2016-02-08 01:15:05 +01:00
displayExclusionOptions()
else:
2016-03-24 06:10:13 +01:00
if not settings["auto"]:
print ("OK, we\'ll only exclude domains in the whitelist.")
def promptForMoreCustomExclusions():
response = query_yes_no("Do you have more domains you want to enter?")
2016-02-08 01:23:40 +01:00
if response == "yes":
2016-02-08 01:15:05 +01:00
return True
else:
return False
def promptForMove(finalFile):
2016-03-24 06:10:13 +01:00
if settings["replace"]:
response = "yes"
else:
2016-03-24 06:10:13 +01:00
response = "no" if settings["auto"] else query_yes_no("Do you want to replace your existing hosts file " +
2016-02-08 01:25:32 +01:00
"with the newly generated file?")
2016-02-08 01:23:40 +01:00
if response == "yes":
moveHostsFileIntoPlace(finalFile)
2016-02-08 01:15:05 +01:00
else:
return False
# End Prompt the User
# Exclusion logic
def displayExclusionOptions():
2016-03-24 06:10:13 +01:00
for exclusionOption in settings["common_exclusions"]:
response = query_yes_no("Do you want to exclude the domain " + exclusionOption + " ?")
2016-02-08 01:23:40 +01:00
if response == "yes":
2016-02-08 01:15:05 +01:00
excludeDomain(exclusionOption)
else:
continue
response = query_yes_no("Do you want to exclude any other domains?")
2016-02-08 01:23:40 +01:00
if response == "yes":
2016-02-08 01:15:05 +01:00
gatherCustomExclusions()
2015-10-29 00:33:16 +01:00
def gatherCustomExclusions():
2016-02-08 01:15:05 +01:00
while True:
# Cross-python Input
domainFromUser = myInput("Enter the domain you want to exclude (e.g. facebook.com): ")
2016-02-08 01:23:40 +01:00
if isValidDomainFormat(domainFromUser):
excludeDomain(domainFromUser)
if promptForMoreCustomExclusions() is False:
2016-02-08 01:15:05 +01:00
return
def excludeDomain(domain):
2016-03-24 06:10:13 +01:00
settings["exclusionregexs"].append(re.compile(settings["exclusionpattern"] + domain))
def matchesExclusions(strippedRule):
2016-02-08 01:15:05 +01:00
strippedDomain = strippedRule.split()[1]
2016-03-24 06:10:13 +01:00
for exclusionRegex in settings["exclusionregexs"]:
if exclusionRegex.search(strippedDomain):
2016-02-08 01:15:05 +01:00
return True
return False
# End Exclusion Logic
# Update Logic
def updateAllSources():
2016-03-24 06:10:13 +01:00
allsources = list(set(settings["sources"]) | set(settings["extensions"]))
2016-02-23 01:20:20 +01:00
for source in allsources:
if os.path.isdir(source):
updateURLs = getUpdateURLsFromFile(source)
if not len(updateURLs):
continue
for updateURL in updateURLs:
print ("Updating source " + os.path.basename(source) + " from " + updateURL)
# Cross-python call
updatedFile = getFileByUrl(updateURL)
try:
updatedFile = updatedFile.replace('\r', '') #get rid of carriage-return symbols
# This is cross-python code
2016-03-24 06:10:13 +01:00
dataFile = open(os.path.join(settings["datapath"], source, settings["datafilenames"]), 'wb')
writeData(dataFile, updatedFile)
dataFile.close()
except:
print ("Skipping.")
def getUpdateURLsFromFile(source):
2016-03-24 06:10:13 +01:00
pathToUpdateFile = os.path.join(settings["datapath"], source, settings["updateurlfilename"])
if os.path.exists(pathToUpdateFile):
updateFile = open(pathToUpdateFile, 'r')
retURLs = updateFile.readlines()
# .strip()
updateFile.close()
else:
retURL = None
printFailure('Warning: Can\'t find the update file for source ' + source + '\n' +
'Make sure that there\'s a file at ' + pathToUpdateFile)
return retURLs
# End Update Logic
2016-01-03 00:57:23 +01:00
def getUpdateURLFromFile(source):
2016-03-24 06:10:13 +01:00
pathToUpdateFile = os.path.join(settings["datapath"], source, settings["updateurlfilename"])
if os.path.exists(pathToUpdateFile):
updateFile = open(pathToUpdateFile, 'r')
2016-02-08 01:15:05 +01:00
retURL = updateFile.readline().strip()
updateFile.close()
else:
retURL = None
printFailure('Warning: Can\'t find the update file for source ' + source + '\n' +
'Make sure that there\'s a file at ' + pathToUpdateFile)
2016-02-08 01:15:05 +01:00
return retURL
# End Update Logic
# File Logic
def createInitialFile():
2016-02-08 01:15:05 +01:00
mergeFile = tempfile.NamedTemporaryFile()
2016-03-24 06:10:13 +01:00
for source in settings["sources"]:
curFile = open(os.path.join(settings["datapath"], source, settings["datafilenames"]), 'r')
2016-02-08 01:15:05 +01:00
#Done in a cross-python way
writeData(mergeFile, curFile.read())
2015-10-29 00:33:16 +01:00
2016-03-24 06:10:13 +01:00
for source in settings["extensions"]:
curFile = open(os.path.join(settings["extensionspath"], source, settings["datafilenames"]), 'r')
2016-02-23 01:20:20 +01:00
#Done in a cross-python way
writeData(mergeFile, curFile.read())
2016-02-08 01:15:05 +01:00
return mergeFile
def removeDupsAndExcl(mergeFile):
2016-03-24 06:10:13 +01:00
numberOfRules = settings["numberofrules"]
if os.path.isfile(settings["whitelistfile"]):
with open(settings["whitelistfile"], "r") as ins:
2016-02-08 01:15:05 +01:00
for line in ins:
if line.rstrip():
2016-03-24 06:10:13 +01:00
settings["exclusions"].append(line)
2016-03-24 06:10:13 +01:00
if not os.path.exists(settings["outputpath"]):
os.makedirs(settings["outputpath"])
2016-03-13 05:17:37 +01:00
2015-10-29 00:33:16 +01:00
# Another mode is required to read and write the file in Python 3
2016-03-13 16:59:25 +01:00
if Python3:
2016-03-24 06:10:13 +01:00
finalFile = open(os.path.join(settings["outputpath"], 'hosts'), 'w+b')
2016-03-13 16:59:25 +01:00
else:
2016-03-24 06:10:13 +01:00
finalFile = open(os.path.join(settings["outputpath"], 'hosts'), 'w+')
2016-03-13 16:59:25 +01:00
mergeFile.seek(0) # reset file pointer
2016-02-08 01:15:05 +01:00
hostnames = set()
hostnames.add("localhost")
hostnames.add("localhost.localdomain")
hostnames.add("local")
hostnames.add("broadcasthost")
2016-03-24 06:10:13 +01:00
exclusions = settings["exclusions"]
2016-02-08 01:15:05 +01:00
for line in mergeFile.readlines():
write = 'true'
2015-10-26 23:16:55 +01:00
# Explicit encoding
line = line.decode("UTF-8")
# replace tabs with space
line = line.replace('\t+', ' ')
# Trim trailing whitespace
line = line.rstrip() + "\n"
2016-02-08 01:15:05 +01:00
# Testing the first character doesn't require startswith
if line[0] == '#' or re.match(r'^\s*$', line[0]):
# Cross-python write
writeData(finalFile, line)
2016-02-08 01:15:05 +01:00
continue
if '::1' in line:
continue
strippedRule = stripRule(line) #strip comments
if len(strippedRule) == 0:
2016-02-08 01:15:05 +01:00
continue
if matchesExclusions(strippedRule):
2016-02-08 01:15:05 +01:00
continue
hostname, normalizedRule = normalizeRule(strippedRule) # normalize rule
2016-03-24 06:10:13 +01:00
for exclude in exclusions:
2016-02-08 01:32:00 +01:00
if exclude in line:
2016-02-08 01:15:05 +01:00
write = 'false'
break
if normalizedRule and (hostname not in hostnames) and (write == 'true'):
writeData(finalFile, normalizedRule)
hostnames.add(hostname)
2016-02-08 01:15:05 +01:00
numberOfRules += 1
2016-03-24 06:10:13 +01:00
settings["numberofrules"] = numberOfRules
2016-02-08 01:15:05 +01:00
mergeFile.close()
return finalFile
def normalizeRule(rule):
result = re.search(r'^[ \t]*(\d+\.\d+\.\d+\.\d+)\s+([\w\.-]+)(.*)', rule)
2016-02-08 01:15:05 +01:00
if result:
hostname, suffix = result.group(2,3)
hostname = hostname.lower().strip() # explicitly lowercase and trim the hostname
2016-02-08 01:15:05 +01:00
if suffix is not '':
# add suffix as comment only, not as a separate host
2016-03-24 06:10:13 +01:00
return hostname, "%s %s #%s\n" % (settings["targetip"], hostname, suffix)
2016-02-08 01:15:05 +01:00
else:
2016-03-24 06:10:13 +01:00
return hostname, "%s %s\n" % (settings["targetip"], hostname)
print ("==>%s<==" % rule)
2016-02-08 01:15:05 +01:00
return None, None
def finalizeFile(finalFile):
writeOpeningHeader(finalFile)
2016-02-08 01:15:05 +01:00
finalFile.close()
# Some sources put comments around their rules, for accuracy we need to strip them
# the comments are preserved in the output hosts file
def stripRule(line):
2016-02-08 01:15:05 +01:00
splitLine = line.split()
2016-02-08 01:32:00 +01:00
if len(splitLine) < 2 :
2016-02-08 01:15:05 +01:00
# just return blank
return ''
else:
return splitLine[0] + ' ' + splitLine[1]
def writeOpeningHeader(finalFile):
finalFile.seek(0) #reset file pointer
2016-02-08 01:28:31 +01:00
fileContents = finalFile.read() #save content
finalFile.seek(0) #write at the top
2016-02-27 04:55:07 +01:00
writeData(finalFile, '# This hosts file is a merged collection of hosts from reputable sources,\n')
writeData(finalFile, '# with a dash of crowd sourcing via Github\n#\n')
writeData(finalFile, '# Date: ' + time.strftime("%B %d %Y", time.gmtime()) + '\n')
if settings["extensions"]:
writeData(finalFile, '# Extensions added to this file: ' + ", ".join(settings["extensions"]) + '\n')
2016-03-24 06:10:13 +01:00
writeData(finalFile, '# Number of unique domains: ' + "{:,}".format(settings["numberofrules"]) + '\n#\n')
writeData(finalFile, '# Fetch the latest version of this file: https://raw.githubusercontent.com/StevenBlack/hosts/master/'+ os.path.join(settings["outputsubfolder"],"") + 'hosts\n')
writeData(finalFile, '# Project home page: https://github.com/StevenBlack/hosts\n#\n')
writeData(finalFile, '# ===============================================================\n')
writeData(finalFile, '\n')
writeData(finalFile, '127.0.0.1 localhost\n')
writeData(finalFile, '127.0.0.1 localhost.localdomain\n')
2016-03-24 10:54:23 +01:00
writeData(finalFile, '127.0.0.1 local\n')
writeData(finalFile, '255.255.255.255 broadcasthost\n')
writeData(finalFile, '::1 localhost\n')
writeData(finalFile, 'fe80::1%lo0 localhost\n')
if platform.system() == 'Linux':
writeData(finalFile, '127.0.1.1 ' + socket.gethostname() + '\n')
writeData(finalFile, '\n')
2016-02-08 01:28:31 +01:00
preamble = os.path.join(BASEDIR_PATH, "myhosts")
if os.path.isfile(preamble):
with open(preamble, "r") as f:
2016-02-08 01:28:31 +01:00
writeData(finalFile, f.read())
finalFile.write(fileContents)
2016-03-24 06:10:13 +01:00
def updateReadmeData():
extensionsKey = "base"
hostsLocation = ""
2016-03-24 06:10:13 +01:00
if settings["extensions"]:
extensionsKey = "-".join(settings["extensions"])
generationData = {}
2016-03-24 06:10:13 +01:00
generationData["location"] = os.path.join(settings["outputsubfolder"], '')
generationData["entries"] = settings["numberofrules"]
2016-03-24 06:10:13 +01:00
settings["readmedata"][extensionsKey] = generationData
with open(settings["readmedatafilename"], 'w') as f:
json.dump(settings["readmedata"], f)
def moveHostsFileIntoPlace(finalFile):
2016-02-08 01:32:00 +01:00
if os.name == 'posix':
dnsCacheFound = False
print ("Moving the file requires administrative privileges. " +
"You might need to enter your password.")
2016-02-08 01:32:00 +01:00
if subprocess.call(["/usr/bin/sudo", "cp", os.path.abspath(finalFile.name), "/etc/hosts"]):
printFailure("Moving the file failed.")
print ("Flushing the DNS Cache to utilize new hosts file...")
2016-02-08 01:32:00 +01:00
if platform.system() == 'Darwin':
dnsCacheFound = True
2016-02-08 01:32:00 +01:00
if subprocess.call(["/usr/bin/sudo", "killall", "-HUP", "mDNSResponder"]):
printFailure("Flushing the DNS Cache failed.")
2016-02-08 01:15:05 +01:00
else:
if os.path.isfile("/etc/rc.d/init.d/nscd"):
dnsCacheFound = True
2016-02-08 01:32:00 +01:00
if subprocess.call(["/usr/bin/sudo", "/etc/rc.d/init.d/nscd", "restart"]):
printFailure("Flushing the DNS Cache failed.")
else:
printSuccess("Flushing DNS by restarting nscd succeeded")
if os.path.isfile("/usr/lib/systemd/system/NetworkManager.service"):
dnsCacheFound = True
2016-02-08 01:32:00 +01:00
if subprocess.call(["/usr/bin/sudo", "/usr/bin/systemctl", "restart", "NetworkManager.service"]):
printFailure("Flushing the DNS Cache failed.")
else:
printSuccess("Flushing DNS by restarting NetworkManager succeeded")
if os.path.isfile("/usr/lib/systemd/system/wicd.service"):
dnsCacheFound = True
if subprocess.call(["/usr/bin/sudo", "/usr/bin/systemctl", "restart", "wicd.service"]):
printFailure("Flushing the DNS Cache failed.")
else:
printSuccess("Flushing DNS by restarting wicd succeeded")
if os.path.isfile("/usr/lib/systemd/system/dnsmasq.service"):
dnsCacheFound = True
if subprocess.call(["/usr/bin/sudo", "/usr/bin/systemctl", "restart", "dnsmasq.service"]):
printFailure("Flushing the DNS Cache failed.")
else:
printSuccess("Flushing DNS by restarting dnsmasq succeeded")
if os.path.isfile("/usr/lib/systemd/system/networking.service"):
dnsCacheFound = True
if subprocess.call(["/usr/bin/sudo", "/usr/bin/systemctl", "restart", "networking.service"]):
printFailure("Flushing the DNS Cache failed.")
else:
printSuccess("Flushing DNS by restarting networking.service succeeded")
if not dnsCacheFound:
printFailure("Unable to determine DNS management tool.")
2016-02-08 01:32:00 +01:00
elif os.name == 'nt':
print ("Automatically moving the hosts file in place is not yet supported.")
print ("Please move the generated file to %SystemRoot%\system32\drivers\etc\hosts")
2016-02-08 01:15:05 +01:00
def removeOldHostsFile(): # hotfix since merging with an already existing hosts file leads to artefacts and duplicates
oldFilePath = os.path.join(BASEDIR_PATH, 'hosts')
open(oldFilePath, 'a').close() # create if already removed, so remove wont raise an error
backupFilePath = os.path.join(BASEDIR_PATH, 'hosts-{0}'.format(time.strftime("%Y-%m-%d-%H-%M-%S")))
shutil.copy(oldFilePath, backupFilePath) # make a backup copy, marking the date in which the list was updated
2016-02-08 01:28:31 +01:00
os.remove(oldFilePath)
open(oldFilePath, 'a').close() # create new empty hostsfile
# End File Logic
# Helper Functions
## {{{ http://code.activestate.com/recipes/577058/ (r2)
def query_yes_no(question, default = "yes"):
"""Ask a yes/no question via raw_input() and return their answer.
"question" is a string that is presented to the user.
"default" is the presumed answer if the user just hits <Enter>.
It must be "yes" (the default), "no" or None (meaning
an answer is required of the user).
The "answer" return value is one of "yes" or "no".
"""
2016-02-08 01:15:05 +01:00
valid = {"yes":"yes", "y":"yes", "ye":"yes",
"no":"no", "n":"no"}
if default is None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while 1:
sys.stdout.write(colorize(question, colors.PROMPT) + prompt)
2015-10-26 23:46:48 +01:00
# Changed to be cross-python
choice = myInput().lower()
if default is not None and choice == '':
return default
elif choice in valid.keys():
return valid[choice]
else:
printFailure("Please respond with 'yes' or 'no' "\
"(or 'y' or 'n').\n")
## end of http://code.activestate.com/recipes/577058/ }}}
def isValidDomainFormat(domain):
2016-02-08 01:32:00 +01:00
if domain == '':
print ("You didn\'t enter a domain. Try again.")
2016-02-08 01:15:05 +01:00
return False
domainRegex = re.compile("www\d{0,3}[.]|https?")
2016-02-08 01:32:00 +01:00
if domainRegex.match(domain):
2016-02-08 01:34:27 +01:00
print ("The domain " + domain + " is not valid. " +
"Do not include www.domain.com or http(s)://domain.com. Try again.")
2016-02-08 01:15:05 +01:00
return False
else:
return True
# Colors
class colors:
2016-02-08 01:15:05 +01:00
PROMPT = '\033[94m'
SUCCESS = '\033[92m'
2016-02-08 01:15:05 +01:00
FAIL = '\033[91m'
ENDC = '\033[0m'
def colorize(text, color):
2016-02-08 01:15:05 +01:00
return color + text + colors.ENDC
def printSuccess(text):
print (colorize(text, colors.SUCCESS))
def printFailure(text):
print (colorize(text, colors.FAIL))
# End Helper Functions
if __name__ == "__main__":
2016-02-08 01:15:05 +01:00
main()