completed first tool of the client
git-svn-id: http://svn.sabayonlinux.org/projects/entropy/trunk@321 cd1c1023-2f26-0410-ae45-c471fc1f0318
This commit is contained in:
42
client/equo
42
client/equo
@@ -24,26 +24,30 @@ import sys
|
||||
import string
|
||||
import equoTools
|
||||
import entropyTools
|
||||
from outputTools import *
|
||||
|
||||
# CONSTANTS
|
||||
APPNAME = "equilibrium"
|
||||
APPVERSION = "1.0"
|
||||
def print_help():
|
||||
entropyTools.print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
entropyTools.print_info("General Options:")
|
||||
entropyTools.print_info(" --help\t\tthis output")
|
||||
entropyTools.print_info(" --version\t\tprint version")
|
||||
entropyTools.print_info(" --verbose\t\tbe more verbose")
|
||||
entropyTools.print_info(" --nocolor\t\tdisable colorized output")
|
||||
entropyTools.print_info(entropyTools.blue("Tools available: "))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("sync"))+entropyTools.yellow("\t\t to sync package repositories"))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("packages"))+entropyTools.yellow("\t to handle packages"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--ask")+"\t\t\t ask before making any changes")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--pretend")+"\t\t just show what would be done")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("void")+entropyTools.red("\t\t\t void void void void void void void"))
|
||||
print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
print_info("General Options:")
|
||||
print_info(" --help\t\tthis output")
|
||||
print_info(" --version\t\tprint version")
|
||||
print_info(" --verbose\t\tbe more verbose")
|
||||
print_info(" --nocolor\t\tdisable colorized output")
|
||||
print_info(blue("Tools available: "))
|
||||
print_info(" \t"+green(bold("repo"))+yellow("\t\t to handle package repositories"))
|
||||
print_info(" \t\t"+green("sync")+red("\t\t\t sync repositories"))
|
||||
print_info(" \t\t"+green("show")+red("\t\t\t show enabled repositories"))
|
||||
print_info(" \t\t"+green("status")+red("\t\t\t show respositories status"))
|
||||
print_info(" \t"+green(bold("packages"))+yellow("\t to handle packages"))
|
||||
print_info(" \t\t"+red("--ask")+"\t\t\t ask before making any changes")
|
||||
print_info(" \t\t"+red("--pretend")+"\t\t just show what would be done")
|
||||
print_info(" \t\t"+green("void")+red("\t\t\t void void void void void void void"))
|
||||
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("database"))+entropyTools.yellow("\t to handle installed packages database"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("void")+entropyTools.red("\t\t\t void void void void void void void"))
|
||||
print_info(" \t"+green(bold("database"))+yellow("\t to handle installed packages database"))
|
||||
print_info(" \t\t"+green("void")+red("\t\t\t void void void void void void void"))
|
||||
|
||||
options = sys.argv[1:]
|
||||
|
||||
@@ -71,10 +75,6 @@ if len(options) < 1 or string.join(options).find("--help") != -1 or string.join(
|
||||
sys.exit(1)
|
||||
|
||||
# sync mirrors tool
|
||||
elif (options[0] == "sync"):
|
||||
#activatorTools.sync(options[1:])
|
||||
sys.exit(0)
|
||||
# tidy tool
|
||||
elif (options[0] == "tidy"):
|
||||
#activatorTools.sync(options[1:], justTidy = True)
|
||||
sys.exit(0)
|
||||
elif (options[0] == "repo"):
|
||||
rc = equoTools.repositories(options[1:])
|
||||
sys.exit(rc)
|
||||
|
||||
@@ -20,8 +20,168 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
'''
|
||||
|
||||
# RETURN STATUSES: 0-255
|
||||
# NEVER USE SYS.EXIT !
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.append('../libraries')
|
||||
from entropyConstants import *
|
||||
from outputTools import *
|
||||
from remoteTools import downloadData
|
||||
from entropyTools import unpackGzip,compareMd5
|
||||
|
||||
def repositories(options):
|
||||
|
||||
# Options available for all the packages submodules
|
||||
myopts = options[1:]
|
||||
equoRequestAsk = False
|
||||
equoRequestPretend = False
|
||||
equoRequestPackagesCheck = False
|
||||
for opt in myopts:
|
||||
if (opt == "--ask"):
|
||||
equoRequestAsk = True
|
||||
elif (opt == "--pretend"):
|
||||
equoRequestPretend = True
|
||||
|
||||
if (options[0] == "sync"):
|
||||
syncRepositories()
|
||||
|
||||
if (options[0] == "status"):
|
||||
for repo in etpRepositories:
|
||||
showRepositoryInfo(repo)
|
||||
|
||||
if (options[0] == "show"):
|
||||
showRepositories()
|
||||
|
||||
# this function shows a list of enabled repositories
|
||||
def showRepositories():
|
||||
print_info(yellow(" * ")+green("Active Repositories:"))
|
||||
repoNumber = 0
|
||||
for repo in etpRepositories:
|
||||
repoNumber += 1
|
||||
print_info(blue("\t#"+str(repoNumber))+bold(" "+etpRepositories[repo]['description']))
|
||||
print_info(red("\t\tPackages URL: ")+green(etpRepositories[repo]['packages']))
|
||||
print_info(red("\t\tDatabase URL: ")+green(etpRepositories[repo]['database']))
|
||||
print_info(red("\t\tRepository name: ")+bold(repo))
|
||||
print_info(red("\t\tRepository database path: ")+blue(etpRepositories[repo]['dbpath']))
|
||||
return 0
|
||||
|
||||
def showRepositoryInfo(reponame):
|
||||
repoNumber = 0
|
||||
for repo in etpRepositories:
|
||||
repoNumber += 1
|
||||
if repo == reponame:
|
||||
break
|
||||
print_info(blue("#"+str(repoNumber))+bold(" "+etpRepositories[reponame]['description']))
|
||||
if os.path.isfile(etpRepositories[reponame]['dbpath']+"/"+etpConst['etpdatabasefile']):
|
||||
status = "active"
|
||||
else:
|
||||
status = "never synced"
|
||||
print_info(red("\tStatus: ")+yellow(status))
|
||||
print_info(red("\tPackages URL: ")+green(etpRepositories[reponame]['packages']))
|
||||
print_info(red("\tDatabase URL: ")+green(etpRepositories[reponame]['database']))
|
||||
print_info(red("\tRepository name: ")+bold(reponame))
|
||||
print_info(red("\tRepository database path: ")+blue(etpRepositories[reponame]['dbpath']))
|
||||
revision = getRepositoryRevision(reponame)
|
||||
mhash = getRepositoryDbFileHash(reponame)
|
||||
|
||||
print_info(red("\tRepository database checksum: ")+mhash)
|
||||
print_info(red("\tRepository revision: ")+green(str(revision)))
|
||||
return 0
|
||||
|
||||
# @returns -1 if the file does not exist
|
||||
# @returns int>0 if the file exists
|
||||
def getRepositoryRevision(reponame):
|
||||
if os.path.isfile(etpRepositories[reponame]['dbpath']+"/"+etpConst['etpdatabaserevisionfile']):
|
||||
f = open(etpRepositories[reponame]['dbpath']+"/"+etpConst['etpdatabaserevisionfile'],"r")
|
||||
revision = int(f.readline().strip())
|
||||
f.close()
|
||||
else:
|
||||
revision = -1
|
||||
return revision
|
||||
|
||||
# @returns -1 if the file does not exist
|
||||
# @returns int>0 if the file exists
|
||||
def getRepositoryDbFileHash(reponame):
|
||||
if os.path.isfile(etpRepositories[reponame]['dbpath']+"/"+etpConst['etpdatabasehashfile']):
|
||||
f = open(etpRepositories[reponame]['dbpath']+"/"+etpConst['etpdatabasehashfile'],"r")
|
||||
mhash = f.readline().strip().split()[0]
|
||||
f.close()
|
||||
else:
|
||||
mhash = "-1"
|
||||
return mhash
|
||||
|
||||
def syncRepositories():
|
||||
# check etpRepositories
|
||||
if len(etpRepositories) == 0:
|
||||
print_error(yellow(" * ")+red("No repositories specified in ")+etpConst['repositoriesconf'])
|
||||
return 127
|
||||
print_info(yellow(" @@ ")+green("Repositories syncronization..."))
|
||||
repoNumber = 0
|
||||
syncErrors = False
|
||||
for repo in etpRepositories:
|
||||
|
||||
repoNumber += 1
|
||||
|
||||
print_info(blue(" #"+str(repoNumber))+bold(" "+etpRepositories[repo]['description']))
|
||||
print_info(red("\tDatabase URL: ")+green(etpRepositories[repo]['database']))
|
||||
print_info(red("\tDatabase local path: ")+green(etpRepositories[repo]['dbpath']))
|
||||
|
||||
# get database lock
|
||||
rc = downloadData(etpRepositories[repo]['database']+"/"+etpConst['etpdatabasedownloadlockfile'],"/dev/null")
|
||||
if rc != "-3": # cannot download database
|
||||
print_error(bold("\tATTENTION -> ")+red("repository is being updated. Try again in few minutes."))
|
||||
syncErrors = True
|
||||
continue
|
||||
|
||||
# starting to download
|
||||
print_info(red("\tDownloading database ")+green(etpConst['etpdatabasefilegzip'])+red(" ..."))
|
||||
# create dir if it doesn't exist
|
||||
if not os.path.isdir(etpRepositories[repo]['dbpath']):
|
||||
print_info(red("\t\tCreating database directory..."))
|
||||
os.makedirs(etpRepositories[repo]['dbpath'])
|
||||
# download
|
||||
downloadData(etpRepositories[repo]['database']+"/"+etpConst['etpdatabasefilegzip'],etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasefilegzip'])
|
||||
|
||||
print_info(red("\tUnpacking database to ")+green(etpConst['etpdatabasefile'])+red(" ..."))
|
||||
unpackGzip(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasefilegzip'])
|
||||
# download etpdatabasehashfile
|
||||
print_info(red("\tDownloading checksum ")+green(etpConst['etpdatabasehashfile'])+red(" ..."))
|
||||
downloadData(etpRepositories[repo]['database']+"/"+etpConst['etpdatabasehashfile'],etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasehashfile'])
|
||||
# checking checksum
|
||||
print_info(red("\tChecking downloaded database ")+green(etpConst['etpdatabasefile'])+red(" ..."), back = True)
|
||||
f = open(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasehashfile'],"r")
|
||||
md5hash = f.readline().strip()
|
||||
md5hash = md5hash.split()[0]
|
||||
f.close()
|
||||
rc = compareMd5(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasefile'],md5hash)
|
||||
if rc:
|
||||
print_info(red("\tDownloaded database status: ")+bold("OK"))
|
||||
else:
|
||||
print_error(red("\tDownloaded database status: ")+yellow("ERROR"))
|
||||
print_error(red("\t An error occured while checking database integrity"))
|
||||
# delete all
|
||||
if os.path.isfile(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasehashfile']):
|
||||
os.remove(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasehashfile'])
|
||||
if os.path.isfile(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasefilegzip']):
|
||||
os.remove(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabasefilegzip'])
|
||||
if os.path.isfile(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabaserevisionfile']):
|
||||
os.remove(etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabaserevisionfile'])
|
||||
syncErrors = True
|
||||
continue
|
||||
|
||||
# download etpdatabaserevisionfile
|
||||
print_info(red("\tDownloading revision ")+green(etpConst['etpdatabaserevisionfile'])+red(" ..."))
|
||||
downloadData(etpRepositories[repo]['database']+"/"+etpConst['etpdatabaserevisionfile'],etpRepositories[repo]['dbpath']+"/"+etpConst['etpdatabaserevisionfile'])
|
||||
|
||||
print_info(red("\tUpdated repository revision: ")+bold(str(getRepositoryRevision(repo))))
|
||||
print_info(yellow("\tUpdate completed"))
|
||||
|
||||
if syncErrors:
|
||||
print_warning(yellow(" @@ ")+red("Something bad happened. Please have a look."))
|
||||
return 128
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
#def getDatabaseRepositories()
|
||||
@@ -2,22 +2,13 @@
|
||||
#
|
||||
# synthax for repositories:
|
||||
#
|
||||
# database repository: where the available packages database is stored
|
||||
# database|server name|<uri>
|
||||
#
|
||||
# binary repository: where packages are stored
|
||||
# packages|server name|<uri>
|
||||
#
|
||||
# NOTE: database/packages are coupled using the same server name
|
||||
# repository: where the available packages and its database are stored
|
||||
# repository|servername (no spaces!)|server description|<packages uri>|<database uri>
|
||||
#
|
||||
# example:
|
||||
# database|Sabayon Linux Official Repository|http://www.sabayonlinux.org/database/
|
||||
# packages|Sabayon Linux Official Repository|http://www.sabayonlinux.org/binhost/
|
||||
# repository|sabayonlinux.org|Sabayon Linux Official Repository|http://www.sabayonlinux.org/packages|http://www.sabayonlinux.org/database
|
||||
#
|
||||
|
||||
# Sabayon Linux database
|
||||
database|Sabayon Linux Official Repository|http://svn.sabayonlinux.org/entropy/database
|
||||
|
||||
# Sabayon Linux packages
|
||||
packages|Sabayon Linux Official Repository|http://svn.sabayonlinux.org/entropy/packages
|
||||
# Sabayon Linux Official Repository
|
||||
repository|sabayonlinux.org|Sabayon Linux Official Repository|http://svn.sabayonlinux.org/entropy/packages|http://svn.sabayonlinux.org/entropy/database
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ ETP_PORTDIR = "/portage"
|
||||
ETP_DISTFILESDIR = "/distfiles"
|
||||
ETP_DBDIR = "/database/"+ETP_ARCH_CONST
|
||||
ETP_DBFILE = "packages.db"
|
||||
ETP_DBCLIENTFILE = "client.db"
|
||||
ETP_CLIENT_REPO_DIR = "/client"
|
||||
ETP_UPLOADDIR = "/upload/"+ETP_ARCH_CONST
|
||||
ETP_STOREDIR = "/store/"+ETP_ARCH_CONST
|
||||
ETP_SMARTAPPSDIR = "/smartapps/"+ETP_ARCH_CONST
|
||||
@@ -173,7 +173,6 @@ etpConst = {
|
||||
'etpdatabasetaintfile': ETP_DBFILE+".tainted", # when this file exists, the database is not synced anymore with the online one
|
||||
'etpdatabasefile': ETP_DBFILE, # Entropy sqlite database file ETP_DIR+ETP_DBDIR+"/packages.db"
|
||||
'etpdatabasefilegzip': ETP_DBFILE+".gz", # Entropy sqlite database file (gzipped)
|
||||
'etpdatabaseclientfile': ETP_DBCLIENTFILE, # Entropy sqlite client database file
|
||||
'packageshashfileext': ".md5", # Extension of the file that contains the checksum of its releated package file
|
||||
|
||||
'databaseloglevel': 1, # Database log level (default: 1 - see database.conf for more info)
|
||||
@@ -199,9 +198,10 @@ etpConst = {
|
||||
|
||||
'distcc-status': False, # used by Enzyme, if True distcc is enabled
|
||||
'distccconf': "/etc/distcc/hosts", # distcc hosts configuration file
|
||||
'etpdatabasedir': ETP_DIR+ETP_DBDIR, #
|
||||
'etpdatabasedir': ETP_DIR+ETP_DBDIR,
|
||||
'etpdatabasefilepath': ETP_DIR+ETP_DBDIR+"/"+ETP_DBFILE,
|
||||
'etpdatabaseclientfilepath': ETP_DIR+ETP_DBDIR+"/"+ETP_DBCLIENTFILE,
|
||||
'etpdatabaseclientdir': ETP_DIR+ETP_CLIENT_REPO_DIR+ETP_DBDIR,
|
||||
|
||||
'etpapi': ETP_API, # Entropy database API revision
|
||||
'headertext': ETP_HEADER_TEXT, # header text that can be outputted to a file
|
||||
'currentarch': ETP_ARCH_CONST, # contains the current running architecture
|
||||
@@ -215,6 +215,7 @@ etpHandlers = {
|
||||
'md5sum': "md5sum.php?arch="+ETP_ARCH_CONST+"&package=", # md5sum handler
|
||||
}
|
||||
|
||||
|
||||
# Create paths
|
||||
if not os.path.isdir(ETP_DIR):
|
||||
import getpass
|
||||
@@ -244,12 +245,9 @@ if not os.path.isdir(ETP_DIR):
|
||||
print "you need to run this as root at least once."
|
||||
sys.exit(100)
|
||||
|
||||
# FIXME: IS THIS REALLY USED BY ANYTHING ????
|
||||
etpSources = {
|
||||
'packagesuri': "", # URIs where are stored binary packages
|
||||
'databaseuri': "", # URIs where are stored entropy files
|
||||
}
|
||||
etpSources['packagesuri'] = []
|
||||
# Client packages/database repositories
|
||||
# used by equo
|
||||
etpRepositories = {}
|
||||
|
||||
if os.path.isfile(etpConst['repositoriesconf']):
|
||||
f = open(etpConst['repositoriesconf'],"r")
|
||||
@@ -258,17 +256,18 @@ if os.path.isfile(etpConst['repositoriesconf']):
|
||||
|
||||
for line in repositoriesconf:
|
||||
line = line.strip()
|
||||
# populate etpSources['packagesuri']
|
||||
if (line.find("packages|") != -1) and (not line.startswith("#")):
|
||||
repouri = line.split("packages|")[len(line.split("packages|"))-1]
|
||||
if repouri.startswith("http://") or repouri.startswith("ftp://") or repouri.startswith("rsync://"):
|
||||
etpSources['packagesuri'].append(repouri)
|
||||
# populate etpSources['databaseuri']
|
||||
elif (line.find("database|") != -1) and (not line.startswith("#")):
|
||||
if (not etpSources['databaseuri']):
|
||||
repouri = line.split("database|")[len(line.split("database|"))-1]
|
||||
if repouri.startswith("http://") or repouri.startswith("ftp://") or repouri.startswith("rsync://"):
|
||||
etpSources['databaseuri'] = repouri
|
||||
# populate etpRepositories
|
||||
if (line.find("repository|") != -1) and (not line.startswith("#")) and (len(line.split("|")) == 5):
|
||||
reponame = line.split("|")[1]
|
||||
repodesc = line.split("|")[2]
|
||||
repopackages = line.split("|")[3]
|
||||
repodatabase = line.split("|")[4]
|
||||
if (repopackages.startswith("http://") or repopackages.startswith("ftp://")) and (repodatabase.startswith("http://") or repodatabase.startswith("ftp://")):
|
||||
etpRepositories[reponame] = {}
|
||||
etpRepositories[reponame]['description'] = repodesc
|
||||
etpRepositories[reponame]['packages'] = repopackages+"/"+etpConst['currentarch']
|
||||
etpRepositories[reponame]['database'] = repodatabase+"/"+etpConst['currentarch']
|
||||
etpRepositories[reponame]['dbpath'] = etpConst['etpdatabaseclientdir']+"/"+reponame+"/"+etpConst['currentarch']
|
||||
|
||||
if (commands.getoutput("q -V").find("portage-utils") != -1):
|
||||
pFindLibrary = "qfile -qC "
|
||||
|
||||
@@ -92,6 +92,19 @@ def md5sum(filepath):
|
||||
m.update(block)
|
||||
block = readfile.read(1024)
|
||||
return m.hexdigest()
|
||||
|
||||
def unpackGzip(gzipfilepath):
|
||||
import gzip
|
||||
filepath = gzipfilepath[:len(gzipfilepath)-3] # remove .gz
|
||||
file = open(filepath,"wb")
|
||||
filegz = gzip.GzipFile(gzipfilepath,"rb")
|
||||
filecont = filegz.readlines()
|
||||
filegz.close()
|
||||
file.writelines(filecont)
|
||||
file.flush()
|
||||
file.close()
|
||||
del filecont
|
||||
return filepath
|
||||
|
||||
# This function creates the .hash file related to the given package file
|
||||
# @returns the complete hash file path
|
||||
@@ -550,8 +563,6 @@ def downloadDatabase(uri):
|
||||
|
||||
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"downloadDatabase: called.")
|
||||
|
||||
import gzip
|
||||
|
||||
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"downloadDatabase: downloading from -> "+extractFTPHostFromUri(uri))
|
||||
|
||||
print_info(green(" * ")+red("Downloading database from ")+bold(extractFTPHostFromUri(uri))+red(" ..."))
|
||||
@@ -571,14 +582,9 @@ def downloadDatabase(uri):
|
||||
|
||||
# On the fly decompression
|
||||
print_info(green(" * ")+red("Decompressing ")+bold(etpConst['etpdatabasefilegzip'])+red(" ..."), back = True)
|
||||
dbfile = open(etpConst['etpdatabasefilepath'],"wb")
|
||||
dbfilegz = gzip.GzipFile(etpConst['etpdatabasedir'] + "/" + etpConst['etpdatabasefilegzip'],"rb")
|
||||
dbcont = dbfilegz.readlines()
|
||||
dbfilegz.close()
|
||||
dbfile.writelines(dbcont)
|
||||
dbfile.flush()
|
||||
dbfile.close()
|
||||
del dbcont
|
||||
|
||||
unpackGzip(etpConst['etpdatabasedir'] + "/" + etpConst['etpdatabasefilegzip'])
|
||||
|
||||
print_info(green(" * ")+red("Decompression of ")+bold(etpConst['etpdatabasefilegzip'])+red(" completed."))
|
||||
|
||||
# downloading revision file
|
||||
|
||||
@@ -33,7 +33,7 @@ remoteLog = logTools.LogFile(level=etpConst['remoteloglevel'],filename = etpCons
|
||||
# example: mirrorLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"testFuncton: called.")
|
||||
|
||||
import timeoutsocket
|
||||
import urllib
|
||||
import urllib2
|
||||
timeoutsocket.setDefaultSocketTimeout(60)
|
||||
|
||||
# Get checksum of a package by running md5sum remotely (using php helpers)
|
||||
@@ -54,7 +54,56 @@ def getRemotePackageChecksum(serverName,filename):
|
||||
remoteLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"getRemotePackageChecksum: requested url -> "+request)
|
||||
|
||||
# now pray the server
|
||||
file = urllib.urlopen(request)
|
||||
file = urllib2.urlopen(request)
|
||||
result = file.readline().strip()
|
||||
return result
|
||||
|
||||
|
||||
|
||||
###################################################
|
||||
# HTTP/FTP equo/download functions
|
||||
###################################################
|
||||
|
||||
def downloadData(url,pathToSave, bufferSize = 8192, checksum = True):
|
||||
remoteLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"downloadFile: called.")
|
||||
|
||||
try:
|
||||
remotefile = urllib2.urlopen(url)
|
||||
except Exception, e:
|
||||
remoteLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_NORMAL,"downloadFile: Exception caught for: "+str(url)+" -> "+str(e))
|
||||
return "-3"
|
||||
try:
|
||||
maxsize = remotefile.headers.get("content-length")
|
||||
except:
|
||||
maxsize = 0
|
||||
pass
|
||||
localfile = open(pathToSave,"w")
|
||||
rsx = "x"
|
||||
while rsx != '':
|
||||
rsx = remotefile.read(bufferSize)
|
||||
__downloadFileCommitData(localfile,rsx,maxsize = maxsize)
|
||||
localfile.flush()
|
||||
localfile.close()
|
||||
#print_info("",back = True)
|
||||
if checksum:
|
||||
# return digest
|
||||
return entropyTools.md5sum(pathToSave)
|
||||
else:
|
||||
# return -2
|
||||
return "-2"
|
||||
|
||||
###################################################
|
||||
# HTTP/FTP equo INTERNAL FUNCTIONS
|
||||
###################################################
|
||||
def __downloadFileCommitData(f, buf, output = True, maxsize = 0):
|
||||
# writing file buffer
|
||||
f.write(buf)
|
||||
# update progress
|
||||
if output:
|
||||
kbytecount = float(f.tell())/1024
|
||||
maxsize = int(maxsize)
|
||||
if maxsize > 0:
|
||||
maxsize = float(int(maxsize))/1024
|
||||
# create text
|
||||
currentText = yellow(" <-> Downloading: ")+green(str(round(kbytecount,1)))+"/"+red(str(round(maxsize,1)))+" kB"
|
||||
# print !
|
||||
print_info(currentText,back = True)
|
||||
43
server/activator
vendored
43
server/activator
vendored
@@ -30,32 +30,33 @@ sys.path.append('../libraries')
|
||||
import entropyTools
|
||||
import activatorTools
|
||||
from entropyConstants import *
|
||||
from outputTools import *
|
||||
|
||||
# CONSTANTS
|
||||
APPNAME = "activator"
|
||||
APPVERSION = "1.0"
|
||||
def print_help():
|
||||
entropyTools.print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
entropyTools.print_info("General Options:")
|
||||
entropyTools.print_info(" --help\t\tthis output")
|
||||
entropyTools.print_info(" --version\t\tprint version")
|
||||
entropyTools.print_info(" --verbose\t\tbe more verbose")
|
||||
entropyTools.print_info(" --nocolor\t\tdisable colorized output")
|
||||
entropyTools.print_info(entropyTools.blue("Tools available: "))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("sync"))+entropyTools.yellow("\t\t to sync packages, database and also do some tidy"))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("tidy"))+entropyTools.yellow("\t\t to just remove binary packages that are not in the Entropy database anymore"))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("packages"))+entropyTools.yellow("\t to manage binary packages"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--ask")+"\t\t\t ask before making any changes")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--pretend")+"\t\t just show what would be done")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--do-packages-check")+"\t after the syncronization, also check packages checksum")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("sync")+entropyTools.red("\t\t\t to sync the binary packages across primary mirrors"))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("database"))+entropyTools.yellow("\t to manage database status and settings [")+entropyTools.bold("database content won't be touched")+entropyTools.yellow("]"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("sync")+entropyTools.red("\t\t\t to sync the database across primary mirrors"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("lock")+entropyTools.red("\t\t\t to lock the database(s) status ["+entropyTools.yellow("DANGEROUS")+entropyTools.red("]")))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("unlock")+entropyTools.red("\t\t\t to unlock the database(s) status ["+entropyTools.yellow("DANGEROUS")+entropyTools.red("]")))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("download-lock")+entropyTools.red("\t\t to lock the download mirror status"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("download-unlock")+entropyTools.red("\t\t to unlock the download mirror status"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("lock-status")+entropyTools.red("\t\t to show the current locks status of the mirrors"))
|
||||
print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
print_info("General Options:")
|
||||
print_info(" --help\t\tthis output")
|
||||
print_info(" --version\t\tprint version")
|
||||
print_info(" --verbose\t\tbe more verbose")
|
||||
print_info(" --nocolor\t\tdisable colorized output")
|
||||
print_info(blue("Tools available: "))
|
||||
print_info(" \t"+green(bold("sync"))+yellow("\t\t to sync packages, database and also do some tidy"))
|
||||
print_info(" \t"+green(bold("tidy"))+yellow("\t\t to just remove binary packages that are not in the Entropy database anymore"))
|
||||
print_info(" \t"+green(bold("packages"))+yellow("\t to manage binary packages"))
|
||||
print_info(" \t\t"+red("--ask")+"\t\t\t ask before making any changes")
|
||||
print_info(" \t\t"+red("--pretend")+"\t\t just show what would be done")
|
||||
print_info(" \t\t"+red("--do-packages-check")+"\t after the syncronization, also check packages checksum")
|
||||
print_info(" \t\t"+green("sync")+red("\t\t\t to sync the binary packages across primary mirrors"))
|
||||
print_info(" \t"+green(bold("database"))+yellow("\t to manage database status and settings [")+bold("database content won't be touched")+yellow("]"))
|
||||
print_info(" \t\t"+green("sync")+red("\t\t\t to sync the database across primary mirrors"))
|
||||
print_info(" \t\t"+green("lock")+red("\t\t\t to lock the database(s) status ["+yellow("DANGEROUS")+red("]")))
|
||||
print_info(" \t\t"+green("unlock")+red("\t\t\t to unlock the database(s) status ["+yellow("DANGEROUS")+red("]")))
|
||||
print_info(" \t\t"+green("download-lock")+red("\t\t to lock the download mirror status"))
|
||||
print_info(" \t\t"+green("download-unlock")+red("\t\t to unlock the download mirror status"))
|
||||
print_info(" \t\t"+green("lock-status")+red("\t\t to show the current locks status of the mirrors"))
|
||||
|
||||
options = sys.argv[1:]
|
||||
|
||||
|
||||
@@ -30,59 +30,60 @@ sys.path.append('../libraries')
|
||||
import entropyTools
|
||||
import enzymeTools
|
||||
from entropyConstants import *
|
||||
from outputTools import *
|
||||
|
||||
# CONSTANTS
|
||||
APPNAME = "enzyme"
|
||||
APPVERSION = "1.0"
|
||||
def print_help():
|
||||
entropyTools.print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
entropyTools.print_info("General Options:")
|
||||
entropyTools.print_info(" --help\t\tthis output")
|
||||
entropyTools.print_info(" --version\t\tprint version")
|
||||
entropyTools.print_info(" --verbose\t\tbe more verbose")
|
||||
entropyTools.print_info(" --nocolor\t\tdisable colorized output")
|
||||
entropyTools.print_info(entropyTools.blue("Tools available: "))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("world"))+entropyTools.yellow("\t\t to build all the possible new packages"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--empty-tree")+"\t\t rebuild all, including updates")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--deep")+"\t\t\t analyzes world dependencies deeply")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--pretend")+"\t\t just show what should be done")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--ask")+"\t\t\t just ask before doing what should be done")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--repackage-installed")+"\t creates binaries of all the installed packages")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--skipfirst")+"\t\t skip the first package in the packages list")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--skip=n")+"\t\t skip N packages")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("build"))+entropyTools.yellow("\t\t to build all the packages specified in <atom(s)>"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--force-rebuild")+"\t\t force the building of the package, nevertheless")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--force-repackage")+"\t force the repackaging of all the possible package")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--deep")+"\t\t\t analyze the dependencies deeply")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--nodeps")+"\t\t do not include dependencies and force compilation")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--use")+"\t\t\t show packages USE flags")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--pretend")+"\t\t just show what should be done")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--ask")+"\t\t\t just ask before doing what should be done")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--ignore-conflicts")+"\t ignore conflicts between packages")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--no-interaction")+"\t disable user interaction, automatic driving")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--simulate-building")+"\t compilations are simulated only")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--skipfirst")+"\t\t skip the first package in the packages list")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--skip=n")+"\t\t skip N packages")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("uninstall"))+entropyTools.yellow("\t to uninstall one or a list of packages"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--pretend")+"\t\t just show what would be done")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--just-prune")+"\t\t with slotted packages, keep only the latest, remove the rest")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("overlay"))+entropyTools.yellow("\t\t to manage overlays"))
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("add")+"\t\t\t to add overlays")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("remove")+"\t\t\t to remove overlays")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("sync")+"\t\t\t to sync overlays (after this you can specify which overlay)")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("list")+"\t\t\t to list overlays")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("sync"))+entropyTools.yellow("\t\t to just sync portage tree"))
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--sync-back")+"\t\t sync between Entropy Portage Tree and the official one")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--only-sync-back")+"\t only sync between Entropy Portage Tree and the official one")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--no-overlay-sync")+"\t disable automatic overlays sync")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("search"))+entropyTools.yellow("\t\t to search a package inside the Entropy Portage repository"))
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("distcc"))+entropyTools.yellow("\t\t distcc manager"))
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--add-host")+"\t\t add a hostname/ip")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--remove-host")+"\t\t remove a hostname/ip")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--enable")+"\t\t enable the DistCC funcionality")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--disable")+"\t\t disable the DistCC funcionality")
|
||||
entropyTools.print_info(" \t\t "+entropyTools.red("--show-hosts")+"\t\t show the currently enabled hosts")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("cleanup"))+entropyTools.yellow("\t\t to clean temporary files"))
|
||||
print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
print_info("General Options:")
|
||||
print_info(" --help\t\tthis output")
|
||||
print_info(" --version\t\tprint version")
|
||||
print_info(" --verbose\t\tbe more verbose")
|
||||
print_info(" --nocolor\t\tdisable colorized output")
|
||||
print_info(blue("Tools available: "))
|
||||
print_info(" \t"+green(bold("world"))+yellow("\t\t to build all the possible new packages"))
|
||||
print_info(" \t\t"+red("--empty-tree")+"\t\t rebuild all, including updates")
|
||||
print_info(" \t\t"+red("--deep")+"\t\t\t analyzes world dependencies deeply")
|
||||
print_info(" \t\t"+red("--pretend")+"\t\t just show what should be done")
|
||||
print_info(" \t\t"+red("--ask")+"\t\t\t just ask before doing what should be done")
|
||||
print_info(" \t\t"+red("--repackage-installed")+"\t creates binaries of all the installed packages")
|
||||
print_info(" \t\t"+red("--skipfirst")+"\t\t skip the first package in the packages list")
|
||||
print_info(" \t\t"+red("--skip=n")+"\t\t skip N packages")
|
||||
print_info(" \t"+green(bold("build"))+yellow("\t\t to build all the packages specified in <atom(s)>"))
|
||||
print_info(" \t\t"+red("--force-rebuild")+"\t\t force the building of the package, nevertheless")
|
||||
print_info(" \t\t"+red("--force-repackage")+"\t force the repackaging of all the possible package")
|
||||
print_info(" \t\t"+red("--deep")+"\t\t\t analyze the dependencies deeply")
|
||||
print_info(" \t\t"+red("--nodeps")+"\t\t do not include dependencies and force compilation")
|
||||
print_info(" \t\t"+red("--use")+"\t\t\t show packages USE flags")
|
||||
print_info(" \t\t"+red("--pretend")+"\t\t just show what should be done")
|
||||
print_info(" \t\t"+red("--ask")+"\t\t\t just ask before doing what should be done")
|
||||
print_info(" \t\t"+red("--ignore-conflicts")+"\t ignore conflicts between packages")
|
||||
print_info(" \t\t"+red("--no-interaction")+"\t disable user interaction, automatic driving")
|
||||
print_info(" \t\t"+red("--simulate-building")+"\t compilations are simulated only")
|
||||
print_info(" \t\t"+red("--skipfirst")+"\t\t skip the first package in the packages list")
|
||||
print_info(" \t\t"+red("--skip=n")+"\t\t skip N packages")
|
||||
print_info(" \t"+green(bold("uninstall"))+yellow("\t to uninstall one or a list of packages"))
|
||||
print_info(" \t\t"+red("--pretend")+"\t\t just show what would be done")
|
||||
print_info(" \t\t"+red("--just-prune")+"\t\t with slotted packages, keep only the latest, remove the rest")
|
||||
print_info(" \t"+green(bold("overlay"))+yellow("\t\t to manage overlays"))
|
||||
print_info(" \t\t "+red("add")+"\t\t\t to add overlays")
|
||||
print_info(" \t\t "+red("remove")+"\t\t\t to remove overlays")
|
||||
print_info(" \t\t "+red("sync")+"\t\t\t to sync overlays (after this you can specify which overlay)")
|
||||
print_info(" \t\t "+red("list")+"\t\t\t to list overlays")
|
||||
print_info(" \t"+green(bold("sync"))+yellow("\t\t to just sync portage tree"))
|
||||
print_info(" \t\t "+red("--sync-back")+"\t\t sync between Entropy Portage Tree and the official one")
|
||||
print_info(" \t\t "+red("--only-sync-back")+"\t only sync between Entropy Portage Tree and the official one")
|
||||
print_info(" \t\t "+red("--no-overlay-sync")+"\t disable automatic overlays sync")
|
||||
print_info(" \t"+green(bold("search"))+yellow("\t\t to search a package inside the Entropy Portage repository"))
|
||||
print_info(" \t"+green(bold("distcc"))+yellow("\t\t distcc manager"))
|
||||
print_info(" \t\t "+red("--add-host")+"\t\t add a hostname/ip")
|
||||
print_info(" \t\t "+red("--remove-host")+"\t\t remove a hostname/ip")
|
||||
print_info(" \t\t "+red("--enable")+"\t\t enable the DistCC funcionality")
|
||||
print_info(" \t\t "+red("--disable")+"\t\t disable the DistCC funcionality")
|
||||
print_info(" \t\t "+red("--show-hosts")+"\t\t show the currently enabled hosts")
|
||||
print_info(" \t"+green(bold("cleanup"))+yellow("\t\t to clean temporary files"))
|
||||
|
||||
options = sys.argv[1:]
|
||||
|
||||
|
||||
@@ -32,36 +32,37 @@ import entropyTools
|
||||
import reagentTools
|
||||
import databaseTools
|
||||
from entropyConstants import *
|
||||
from outputTools import *
|
||||
|
||||
# CONSTANTS
|
||||
APPNAME = "reagent"
|
||||
APPVERSION = "1.0"
|
||||
def print_help():
|
||||
entropyTools.print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
entropyTools.print_info("General Options:")
|
||||
entropyTools.print_info(" --help\t\tthis output")
|
||||
entropyTools.print_info(" --version\t\tprint version")
|
||||
entropyTools.print_info(" --nocolor\t\tdisable colorized output")
|
||||
entropyTools.print_info(entropyTools.blue("Tools available: "))
|
||||
entropyTools.print_info(" \t"+entropyTools.green("enzyme")+entropyTools.yellow("\t\t to analyze enzyme store directory"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--force-bump")+"\t\t to force the revision bumping of the package entries")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("database"))+entropyTools.yellow("\t Entropy database tool manager."))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("--initialize")+"\t\t (Re)Initialize the Entropy packages database [DO NOT USE THIS]")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.red("statistics")+"\t\t Show Entropy database statistics.")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("search")+"\t\t\t Search a package inside the Entropy packages database")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("dump-package-info")+"\t Dump the stored information of package atom(s) to a file")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("inject-package-info")+"\t Inject an Entropy dump inside the database (file path is mandatory)")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("restore-package-info")+"\t Reinitialize a package entry looking at the current install")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green(entropyTools.bold("remove"))+"\t\t\t Remove a package or a list of packages")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("create-empty-database")+"\t Create an empty Entropy database file in the specified <path>")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("stabilize")+"\t\t Mark as stable a package, a list of packages, world")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("unstabilize")+"\t\t Mark as unstable a package, a list of packages, world")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green("md5check")+"\t\t Check digest of a package, a list of packages, world")
|
||||
#entropyTools.print_info(" \t\t"+entropyTools.green(entropyTools.bold("orphans"))+"\t\t\t Dump the list of files that don't belong on any installed package")
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green(entropyTools.bold("sanity-check"))+"\t\t Do a quick check on the database to assure data integrity")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("smartapps"))+entropyTools.yellow("\t Entropy application tool to create self-dependant applications [EXPERIMENTAL]"))
|
||||
entropyTools.print_info(" \t\t"+entropyTools.green(entropyTools.bold("create"))+"\t\t\t Create a smartapp package using the package names provided")
|
||||
entropyTools.print_info(" \t"+entropyTools.green(entropyTools.bold("cleanup"))+entropyTools.yellow("\t\t to clean temporary files"))
|
||||
print_info("Sabayon Linux "+APPNAME+" (C - 2007)")
|
||||
print_info("General Options:")
|
||||
print_info(" --help\t\tthis output")
|
||||
print_info(" --version\t\tprint version")
|
||||
print_info(" --nocolor\t\tdisable colorized output")
|
||||
print_info(entropyTools.blue("Tools available: "))
|
||||
print_info(" \t"+green("enzyme")+yellow("\t\t to analyze enzyme store directory"))
|
||||
print_info(" \t\t"+red("--force-bump")+"\t\t to force the revision bumping of the package entries")
|
||||
print_info(" \t"+green(bold("database"))+yellow("\t Entropy database tool manager."))
|
||||
print_info(" \t\t"+red("--initialize")+"\t\t (Re)Initialize the Entropy packages database [DO NOT USE THIS]")
|
||||
print_info(" \t\t"+red("statistics")+"\t\t Show Entropy database statistics.")
|
||||
print_info(" \t\t"+green("search")+"\t\t\t Search a package inside the Entropy packages database")
|
||||
print_info(" \t\t"+green("dump-package-info")+"\t Dump the stored information of package atom(s) to a file")
|
||||
print_info(" \t\t"+green("inject-package-info")+"\t Inject an Entropy dump inside the database (file path is mandatory)")
|
||||
print_info(" \t\t"+green("restore-package-info")+"\t Reinitialize a package entry looking at the current install")
|
||||
print_info(" \t\t"+green(bold("remove"))+"\t\t\t Remove a package or a list of packages")
|
||||
print_info(" \t\t"+green("create-empty-database")+"\t Create an empty Entropy database file in the specified <path>")
|
||||
print_info(" \t\t"+green("stabilize")+"\t\t Mark as stable a package, a list of packages, world")
|
||||
print_info(" \t\t"+green("unstabilize")+"\t\t Mark as unstable a package, a list of packages, world")
|
||||
print_info(" \t\t"+green("md5check")+"\t\t Check digest of a package, a list of packages, world")
|
||||
#print_info(" \t\t"+green(bold("orphans"))+"\t\t\t Dump the list of files that don't belong on any installed package")
|
||||
print_info(" \t\t"+green(bold("sanity-check"))+"\t\t Do a quick check on the database to assure data integrity")
|
||||
print_info(" \t"+green(bold("smartapps"))+yellow("\t Entropy application tool to create self-dependant applications [EXPERIMENTAL]"))
|
||||
print_info(" \t\t"+green(bold("create"))+"\t\t\t Create a smartapp package using the package names provided")
|
||||
print_info(" \t"+green(bold("cleanup"))+yellow("\t\t to clean temporary files"))
|
||||
|
||||
options = sys.argv[1:]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user