1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-01-26 22:56:15 +01:00
status: 
- use new file metadata which provides checksum, size and mtime 
- don't list unmodified files
- fix some conditions where status was too stupid so far
update: 
- much faster now, since only new or changed files are downloaded
- print revision number
checkout:
- mark project directory as such (to be used later)
diff:
- faster, since 'status' is faster
- work against local copy
checkin: 
- update package metadata from specfile 
- fix argument handling 
add: 
- ignore .osc and other files
other changes:
- sanitize argument handling, so most commands can work with
  arbitrary files/directories as arguments (work is always done per package)
- add history command (doesn't seem to be working yet)
- on first usage, ask for username password on first usage, 
  and store them in .oscrc (.netrc can still be used)
This commit is contained in:
Dr. Peter Poeml 2006-05-19 20:13:29 +00:00
parent 0871a8ce3f
commit 4b83218cf6
6 changed files with 575 additions and 249 deletions

46
README
View File

@ -10,6 +10,10 @@ https://forgesvn1.novell.com/svn/opensuse/trunk/buildservice/src/clientlib/pytho
INSTALLATION:
RPM packages are here (yum repository):
http://repos.opensuse.org/opensuse/repositories/openSUSE:Tools/
To install from svn, do
python setup.py build
python setup.py install
# create a symlink 'osc' in your path pointing to osc.py.
@ -28,10 +32,8 @@ on SUSE anyway):
CONFIGURATION:
For authentication, put your account data into your ~/.netrc file, like this
line:
machine api.opensuse.org login $login password $pass
osc uses authentication data if it finds it in .netrc, otherwise it will ask
for username/password once, and store it in ~/.oscrc.
@ -49,6 +51,7 @@ osc co Apache subversion foo # single file
# update working copy
osc up
osc up <directory>
osc up * # from within a project dir, update all packages
# check in
osc ci # current dir
@ -58,20 +61,22 @@ osc ci file1 file2 ...
# show status
osc st
osc st <directory>
osc st file1 file2 ...
# initialize a source directory to be a
# working copy of project <prj> package <pac>
osc init <prj> <pac>
# schedule file foo to be added / deleted
osc add foo
osc rm foo
# schedule files foo to be added / deleted
osc add file1 file2 ...
osc rm file1 file2 ...
# add all unknown files and remove all missing files
# add all unknown files AND remove all missing files
osc addremove
# show diff
osc diff [file]
osc diff # current dir
osc diff file1 file2 ...
# show build results (xml)
osc results
@ -90,3 +95,26 @@ osc meta Apache
osc meta Apache subversion
osc id username
HINT FOR W3M USERS
Putting the following in the file ~/.w3m/passwd will make
w3m know the credentials for the buildservice servers:
"""
host api.opensuse.org
port 80
realm Authentication required
login foo
password bar
host build.opensuse.org
port 80
realm openSUSE Build Service
login foo
password bar
"""
chmod 0600 ~/.w3m/passwd

17
TODO
View File

@ -1,14 +1,27 @@
- implement 'info' command
- implement 'mv' command
- implement 'trigger-rebuild'
update: handle local modifications
checkin:
- fix argument handling
- aggregate files to check in per directory
- handle error if PUT fails, so the change is not committed to
localmeta
diff: use rev numbers in diff header lines
results: aggregate results of all packages in a project
split functionality that needs prj/pac as commandline arguments into a seperate tool (oscremote)
implement a package search / indexing
edit user data
<watchlist>
<project name="ASCIIParadize"/>
<project name="crashtest"/>
</watchlist>

View File

@ -1,4 +1,8 @@
#!/usr/bin/env python
# this wrapper exists so it can be put into /usr/bin, but still allows the
# python module to be called within the source directory during development
from osc import commandline
from osc.core import init_basicauth

View File

@ -7,7 +7,6 @@
from core import *
def main():
cmd = sys.argv[1]
@ -47,18 +46,22 @@ def main():
print ''.join(show_project_meta(project))
elif cmd == 'diff':
wd = os.curdir
package = store_read_package(wd)
project = store_read_project(wd)
if len(sys.argv) > 2:
filename = sys.argv[2]
if filename:
print get_source_file_diff(project, package, filename)
else:
args = parseargs()
pacs = findpacs(args)
for p in pacs:
if p.todo == []:
for i in p.filenamelist:
if p.status(i) == 'M':
p.todo.append(i)
d = []
for filename in meta_get_filelist(project, package):
d.append(get_source_file_diff(project, package, filename))
print ''.join(d)
for filename in p.todo:
d.append('Index: %s\n' % filename)
d.append('===================================================================\n')
d.append(get_source_file_diff(p.dir, filename, p.rev))
if d:
print ''.join(d)
elif cmd == 'co' or cmd == 'checkout':
@ -85,31 +88,20 @@ def main():
elif cmd == 'st' or cmd == 'status':
args = parseargs()
pacs = findpacs(args)
for arg in args:
for p in pacs:
if os.path.isfile(arg):
wd = os.path.dirname(arg)
filenames = [ os.path.basename(arg) ]
elif os.path.isdir(arg):
wd = arg
package = store_read_package(wd)
project = store_read_project(wd)
filenames = meta_get_filelist(project, package)
# no files given as argument? Take all files in current dir
if not p.todo:
p.todo = p.filenamelist + p.filenamelist_unvers
# add files which are not listed in _meta
for i in os.listdir(arg):
if i not in filenames and i not in exclude_stuff:
filenames.insert(0, i)
os.chdir(wd)
check_store_version()
filelist = localmeta_get_filelist()
for filename in filenames:
s = get_file_status(project, package, filename, filelist=filelist)
if not s.startswith(' '):
print s
for filename in p.todo:
s = p.status(filename)
if s == 'F':
print statfrmt('!', filename)
elif s != ' ':
print statfrmt(s, filename)
elif cmd == 'add':
@ -123,155 +115,122 @@ def main():
if not os.path.exists(filename):
print "file '%s' does not exist" % filename
sys.exit(1)
for filename in filenames:
localmeta_addfile(filename)
print 'A ', filename
pacs = findpacs(filenames)
for pac in pacs:
for filename in pac.todo:
if filename in exclude_stuff:
continue
pac.addfile(filename)
print statfrmt('A', filename)
elif cmd == 'addremove':
args = parseargs()
pacs = findpacs(args)
for p in pacs:
for arg in args:
p.todo = p.filenamelist + p.filenamelist_unvers
if os.path.isfile(arg):
wd = os.path.dirname(arg)
filenames = [ os.path.basename(arg) ]
elif os.path.isdir(arg):
wd = arg
package = store_read_package(wd)
project = store_read_project(wd)
filenames = meta_get_filelist(project, package)
for filename in p.todo:
if filename in exclude_stuff:
continue
state = p.status(filename)
if state == '?':
p.addfile(filename)
print statfrmt('A', filename)
elif state == '!':
p.put_on_deletelist(filename)
p.write_deletelist()
os.unlink(os.path.join(p.storedir, filename))
print statfrmt('D', filename)
# add files which are not listed in _meta
for i in os.listdir(arg):
if i not in filenames and i not in exclude_stuff:
filenames.insert(0, i)
filelist = localmeta_get_filelist()
for filename in filenames:
st = get_file_status(project, package, filename, filelist=filelist)
if st.startswith('?'):
localmeta_addfile(filename)
print 'A ', filename
elif st.startswith('!'):
print 'D ', filename
localmeta_removefile(filename)
elif cmd == 'ci' or cmd == 'checkin':
init_basicauth()
args = parseargs()
for arg in args:
pacs = findpacs(args)
if os.path.isfile(arg):
wd = os.path.dirname(arg)
filenames = [ os.path.basename(arg) ]
elif os.path.isdir(arg):
wd = arg
package = store_read_package(wd)
project = store_read_project(wd)
filenames = meta_get_filelist(project, package)
for p in pacs:
p.todo = p.filenamelist_unvers + p.filenamelist
# add files which are not listed in _meta
for i in os.listdir(arg):
if i not in filenames and i not in exclude_stuff:
filenames.insert(0, i)
os.chdir(wd)
files_to_send = []
files_to_delete = []
filelist = localmeta_get_filelist()
for filename in filenames:
st = get_file_status(project, package, filename, filelist=filelist)
if st.startswith('A') or st.startswith('M'):
files_to_send.append(filename)
for filename in p.todo:
st = p.status(filename)
if st == 'A' or st == 'M':
p.todo_send.append(filename)
print 'Sending %s' % filename
elif st.startswith('D'):
files_to_delete.append(filename)
elif st == 'D':
p.todo_delete.append(filename)
print 'Deleting %s' % filename
if not files_to_send and not files_to_delete:
print 'nothing to do'
sys.exit(0)
if not p.todo_send and not p.todo_delete:
print 'nothing to do for package %s' % p.name
continue
print 'Transmitting file data ',
for filename in files_to_send:
put_source_file(project, package, filename)
copy_file(filename, os.path.join(store, filename))
for filename in files_to_delete:
del_source_file(project, package, filename)
for filename in p.todo_send:
put_source_file(p.prjname, p.name, os.path.join(p.dir, filename))
#copy_file(filename, os.path.join(store, filename))
for filename in p.todo_delete:
del_source_file(p.prjname, p.name, filename)
p.to_be_deleted.remove(filename)
p.update_filesmeta()
p.write_deletelist()
print
elif cmd == 'up' or cmd == 'update':
args = parseargs()
pacs = findpacs(args)
for arg in args:
if os.path.isfile(arg):
wd = os.path.dirname(arg)
filenames = [ os.path.basename(arg) ]
elif os.path.isdir(arg):
wd = arg
package = store_read_package(wd)
project = store_read_project(wd)
## add files which are not listed in _meta
#for i in os.listdir(arg):
# if i not in filenames and i not in exclude_stuff:
# filenames.insert(0, i)
olddir = os.getcwd()
os.chdir(wd)
check_store_version()
for p in pacs:
# save filelist before replacing the meta file
filenames = localmeta_get_filelist()
os.chdir(store)
# update filelist
f = open('_files', 'w')
f.write(''.join(show_files_meta(project, package)))
f.close()
saved_filenames = p.filenamelist
p.update_filesmeta()
p = Package(p.dir)
# which files do no longer exist upstream?
disappeared = []
upstream_files = meta_get_filelist(project, package)
for filename in filenames:
if filename not in upstream_files:
for filename in saved_filenames:
if filename not in p.filenamelist:
disappeared.append(filename)
for filename in filenames:
for filename in saved_filenames:
if filename in disappeared:
print 'D %s' % filename
os.unlink(filename)
print statfrmt('D', filename)
p.delfile(filename)
continue
get_source_file(project, package, filename)
wcfilename = os.path.join(os.pardir, os.path.basename(filename))
for filename in p.filenamelist:
if not os.path.exists(wcfilename):
print 'A %s' % filename
copy_file(filename, wcfilename)
elif dgst(wcfilename) != dgst(filename):
print 'U %s' % filename
copy_file(filename, wcfilename)
else:
state = p.status(filename)
if state == 'M':
print 'file %s is locally modified... fixme' % filename
p.updatefile(filename)
print statfrmt('U', filename)
elif state == '!':
p.updatefile(filename)
print 'Restored \'%s\'' % filename
elif state == 'F':
p.updatefile(filename)
print statfrmt('A', filename)
elif state == ' ':
pass
# get current meta file
f = open('_meta', 'w')
f.write(''.join(show_package_meta(project, package)))
f.close()
os.chdir(olddir)
p.update_pacmeta()
print 'At revision %s.' % p.rev
@ -283,25 +242,26 @@ def main():
sys.exit(1)
args = parseargs()
pacs = findpacs(args)
for arg in args:
for p in pacs:
olddir = os.getcwd()
for filename in p.todo:
p.put_on_deletelist(filename)
p.write_deletelist()
try:
os.unlink(os.path.join(p.dir, filename))
os.unlink(os.path.join(p.storedir, filename))
except:
pass
print statfrmt('D', filename)
wd = os.path.dirname(arg) or os.curdir
filename = arg
os.chdir(wd)
localmeta_removefile(filename)
print 'D %s' % filename
os.chdir(olddir)
elif cmd == 'id':
print ''.join(get_user_id(sys.argv[2]))
elif cmd == 'platforms':
if len(sys.argv) > 2:
project = sys.argv[2]
@ -310,7 +270,6 @@ def main():
print '\n'.join(get_platforms())
elif cmd == 'results_meta':
wd = os.curdir
package = store_read_package(wd)
@ -321,6 +280,7 @@ def main():
else:
for platform in get_platforms_of_project(project):
print ''.join(show_results_meta(project, package, platform))
elif cmd == 'results':
if len(sys.argv) > 3:
@ -347,9 +307,19 @@ def main():
arch = sys.argv[3]
print ''.join(get_log(project, package, platform, arch))
elif cmd == 'hist' or cmd == 'history':
args = parseargs()
pacs = findpacs(args)
for p in pacs:
print ''.join(get_history(p.prjname, p.name))
else:
print "unknown command '%s'" % cmd
if __name__ == '__main__':
init_basicauth()
main()

View File

@ -5,20 +5,15 @@
# and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version.
__version__ = '0.2'
__version__ = '0.3'
import os
import sys
import urllib2
import netrc
from urlparse import urlunsplit
import cElementTree as ET
from cStringIO import StringIO
# the needed entry in .netrc looks like this:
# machine api.opensuse.org login your_login password your_pass
info = netrc.netrc()
username, account, password = info.authenticators("api.opensuse.org")
from xml.dom.ext.reader import Sax2
from xml.dom.ext import PrettyPrint
@ -31,6 +26,222 @@ store = '.osc'
exclude_stuff = [store, '.svn', 'CVS']
class File:
"""represent a file, including its metadata"""
def __init__(self, name, md5, size, mtime):
self.name = name
self.md5 = md5
self.size = size
self.mtime = mtime
def __str__(self):
return self.name
class Package:
"""represent a package (its directory) and read/keep/write its metadata"""
def __init__(self, workingdir):
self.dir = workingdir
self.storedir = os.path.join(self.dir, store)
check_store_version(self.dir)
self.prjname = store_read_project(self.dir)
self.name = store_read_package(self.dir)
files_tree = read_filemeta(self.dir)
files_tree_root = files_tree.getroot()
self.rev = files_tree_root.get('rev')
self.filenamelist = []
self.filelist = []
for node in files_tree_root.findall('entry'):
f = File(node.get('name'),
node.get('md5'),
node.get('size'),
node.get('mtime'))
self.filelist.append(f)
self.filenamelist.append(f.name)
self.to_be_deleted = read_tobedeleted(self.dir)
self.todo = []
self.todo_send = []
self.todo_delete = []
# gather unversioned files (the ones not listed in _meta)
self.filenamelist_unvers = []
for i in os.listdir(self.dir):
if i in exclude_stuff:
continue
if not i in self.filenamelist:
self.filenamelist_unvers.append(i)
def addfile(self, n):
st = os.stat(os.path.join(self.dir, n))
f = File(n, dgst(os.path.join(self.dir, n)), st[6], st[8])
self.filelist.append(f)
self.filenamelist.append(n)
self.filenamelist_unvers.remove(n)
copy_file(os.path.join(self.dir, n), os.path.join(self.storedir, n))
def delfile(self, n):
os.unlink(os.path.join(self.dir, n))
os.unlink(os.path.join(self.storedir, n))
def put_on_deletelist(self, n):
if n not in self.to_be_deleted:
self.to_be_deleted.append(n)
def write_deletelist(self):
fname = os.path.join(self.storedir, '_to_be_deleted')
f = open(fname, 'w')
f.write('\n'.join(self.to_be_deleted))
f.write('\n')
f.close()
def updatefile(self, n):
filename = os.path.join(self.dir, n)
storefilename = os.path.join(self.storedir, n)
mtime = int(self.findfilebyname(n).mtime)
get_source_file(self.prjname, self.name, n, targetfilename=filename)
os.utime(filename, (-1, mtime))
copy_file(filename, storefilename)
os.utime(storefilename, (-1, mtime))
def update_filesmeta(self):
meta = ''.join(show_files_meta(self.prjname, self.name))
f = open(os.path.join(self.storedir, '_files'), 'w')
f.write(meta)
f.close()
def update_pacmeta(self):
meta = ''.join(show_package_meta(self.prjname, self.name))
f = open(os.path.join(self.storedir, '_meta'), 'w')
f.write(meta)
f.close()
def findfilebyname(self, n):
for i in self.filelist:
if i.name == n:
return i
def status(self, n):
"""
status can be:
file storefile file present STATUS
exists exists in _files
x x - 'A'
x x x 'M', if digest differs, else ' '
x - - '?'
x - x 'D' and listed in _to_be_deleted
- x x '!'
- x - 'D' (when file in working copy is already deleted)
- - x 'F' (new in repo, but not yet in working copy)
- - - NOT DEFINED
"""
known_by_meta = False
exists = False
exists_in_store = False
if n in self.filenamelist:
known_by_meta = True
if os.path.exists(os.path.join(self.dir, n)):
exists = True
if os.path.exists(os.path.join(self.storedir, n)):
exists_in_store = True
if exists and not exists_in_store and known_by_meta:
state = 'D'
elif n in self.to_be_deleted:
state = 'D'
elif exists and exists_in_store and known_by_meta:
#print self.findfilebyname(n)
if dgst(os.path.join(self.dir, n)) != self.findfilebyname(n).md5:
state = 'M'
else:
state = ' '
elif exists and not exists_in_store and not known_by_meta:
state = '?'
elif exists and exists_in_store and not known_by_meta:
state = 'A'
elif not exists and exists_in_store and known_by_meta:
state = '!'
elif not exists and not exists_in_store and known_by_meta:
state = 'F'
elif not exists and exists_in_store and not known_by_meta:
state = 'D'
elif not exists and not exists_in_store and not known_by_meta:
print '%s: not exists and not exists_in_store and not nown_by_meta' % n
print 'this code path should never be reached!'
sys.exit(1)
return state
def merge(self, otherpac):
self.todo += otherpac.todo
def __str__(self):
r = """
name: %s
prjname: %s
workingdir: %s
localfilelist: %s
rev: %s
'todo' files: %s
""" % (self.name,
self.prjname,
self.dir,
'\n '.join(self.filenamelist),
self.rev,
self.todo)
return r
def findpacs(files):
pacs = []
for f in files:
if f in exclude_stuff:
break
p = filedir_to_pac(f)
known = None
for i in pacs:
if i.name == p.name:
known = i
break
if known:
i.merge(p)
else:
pacs.append(p)
return pacs
def read_filemeta(dir):
return ET.parse(os.path.join(dir, store, '_files'))
def read_tobedeleted(dir):
r = []
fname = os.path.join(dir, store, '_to_be_deleted')
if os.path.exists(fname):
for i in open(fname, 'r').readlines():
r.append(i.strip())
return r
def parseargs():
if len(sys.argv) > 2:
args = sys.argv[2:]
@ -39,12 +250,46 @@ def parseargs():
return args
def filedir_to_pac(f):
if os.path.isdir(f):
wd = f
p = Package(wd)
elif os.path.isfile(f):
wd = os.path.dirname(f)
if wd == '':
wd = os.curdir
p = Package(wd)
p.todo = [ os.path.basename(f) ]
else:
wd = os.path.dirname(f)
if wd == '':
wd = os.curdir
p = Package(wd)
p.todo = [ os.path.basename(f) ]
#else:
# print
# print 'error: %s is neither a valid file or directory' % f
# sys.exit(1)
return p
def statfrmt(statusletter, filename):
return '%s %s' % (statusletter, filename)
def makeurl(l):
"""given a list of path compoments, construct a complete URL"""
return urlunsplit((scheme, netloc, '/'.join(l), '', ''))
def copy_file(src, dst):
# fixme: preserve mtime by default?
s = open(src)
d = open(dst, 'w')
while 1:
@ -55,8 +300,65 @@ def copy_file(src, dst):
d.close()
def readauth():
"""look for the credentials. If there aren't any, ask and store them"""
#
# try .netrc first
#
# the needed entry in .netrc looks like this:
# machine api.opensuse.org login your_login password your_pass
# but it is not able for credentials containing spaces
import netrc
global username, password
try:
info = netrc.netrc()
username, account, password = info.authenticators(netloc)
return username, password
except (IOError, TypeError):
pass
#
# try .oscrc next
#
import ConfigParser
conffile = os.path.expanduser('~/.oscrc')
if os.path.exists(conffile):
config = ConfigParser.ConfigParser()
config.read(conffile)
username = config.get(netloc, 'user')
password = config.get(netloc, 'pass')
return username, password
#
# create .oscrc
#
import getpass
print >>sys.stderr, \
"""your user account / password are not configured yet.
You will be asked for them below, and they will be stored in
%s for later use.
""" % conffile
username = raw_input('Username: ')
password = getpass.getpass()
fd = open(conffile, 'w')
os.chmod(conffile, 0600)
print >>fd, '[%s]\nuser: %s\npass: %s' % (netloc, username, password)
fd.close()
return username, password
def init_basicauth():
username, password = readauth()
passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
# this creates a password manager
passmgr.add_password(None, netloc, username, password)
@ -98,21 +400,30 @@ def init_package_dir(project, package, dir):
return
def check_store_version():
def check_store_version(dir):
versionfile = os.path.join(dir, store, '_osclib_version')
try:
v = open(os.path.join(store, '_osclib_version')).read().strip()
v = open(versionfile).read().strip()
except:
v = ''
if v == '':
print 'error: "%s" is not an osc working copy' % dir
sys.exit(1)
if v != __version__:
if v == '0.2':
# 0.2 is fine, no migration needed
f = open(versionfile, 'w')
f.write(__version__ + '\n')
f.close()
return
print
print 'the osc metadata of your working copy'
print ' %s' % os.getcwd()
print 'the osc metadata of your working copy "%s"' % dir
print 'has the wrong version (%s), should be %s' % (v, __version__)
print 'please do a fresh checkout'
print
sys.exit(1)
def meta_get_packagelist(prj):
@ -158,6 +469,7 @@ def localmeta_addfile(filename):
o = open(os.path.join(store, '_files'), 'w')
PrettyPrint(doc, stream=o)
o.close()
def localmeta_removefile(filename):
@ -195,6 +507,7 @@ def get_slash_source():
r.sort()
return r
def show_project_meta(prj):
f = urllib2.urlopen(makeurl(['source', prj, '_meta']))
return f.readlines()
@ -204,22 +517,49 @@ def show_package_meta(prj, pac):
f = urllib2.urlopen(makeurl(['source', prj, pac, '_meta']))
return f.readlines()
def show_files_meta(prj, pac):
f = urllib2.urlopen(makeurl(['source', prj, pac]))
return f.readlines()
def read_meta_from_spec(specfile):
"""read Name, Summary and %description from spec file"""
in_descr = False
descr = []
if not os.path.isfile(specfile):
print 'file \'%s\' is not a readable file' % specfile
return None
for line in open(specfile, 'r'):
if line.startswith('Name:'):
name = line.split(':')[1].strip()
if line.startswith('Summary:'):
summary = line.split(':')[1].strip()
if line.startswith('%description'):
in_descr = True
continue
if in_descr and line.startswith('%'):
break
if in_descr:
descr.append(line)
return name, summary, descr
def get_user_id(user):
u = makeurl(['person', user])
f = urllib2.urlopen(u)
return f.readlines()
def get_source_file(prj, package, filename):
def get_source_file(prj, package, filename, targetfilename=None):
u = makeurl(['source', prj, package, filename])
#print 'checking out', u
f = urllib2.urlopen(u)
o = open(filename, 'w')
o = open(targetfilename or filename, 'w')
while 1:
buf = f.read(BUFSIZE)
if not buf: break
@ -227,84 +567,22 @@ def get_source_file(prj, package, filename):
o.close()
def dgst(file):
if not os.path.exists(file):
return None
#if not os.path.exists(file):
#return None
import sha
s = sha.new()
import md5
s = md5.new()
f = open(file, 'r')
while 1:
buf = f.read(BUFSIZE)
if not buf: break
s.update(buf)
return s.digest()
return s.hexdigest()
def get_file_status(prj, package, filename, filelist=None):
"""
status can be:
file storefile file present STATUS
exists exists in _files
x x - 'D'
x x x 'M', if digest differs, else ' '
x - - '?'
x - x 'A'
- x x '!'
- x - 'D' (when file in working copy is already deleted)
- - x NOT DEFINED
- - - NEVER REACHED
"""
known_by_meta = False
exists = False
exists_in_store = False
if not filelist:
filelist = localmeta_get_filelist()
if filename in filelist:
known_by_meta = True
if os.path.exists(filename):
exists = True
if os.path.exists(os.path.join(store, filename)):
exists_in_store = True
if exists and exists_in_store and not known_by_meta:
state = 'D'
elif exists and exists_in_store and known_by_meta:
if dgst(filename) != dgst(os.path.join(store, filename)):
state = 'M'
else:
state = ' '
elif exists and not exists_in_store and not known_by_meta:
state = '?'
elif exists and not exists_in_store and known_by_meta:
state = 'A'
elif not exists and exists_in_store and known_by_meta:
state = '!'
elif not exists and not exists_in_store and known_by_meta:
print '%s: not exists and not exists_in_store and known_by_meta' % filename
print 'this state is undefined!'
sys.exit(1)
elif not exists and exists_in_store and not known_by_meta:
state = 'D'
elif not exists and not exists_in_store and not known_by_meta:
print '%s: not exists and not exists_in_store and not nown_by_meta' % filename
print 'this code path should never be reached!'
sys.exit(1)
return '%s %s' % (state, filename)
def get_source_file_diff(prj, package, filename):
def get_source_file_diff_upstream(prj, package, filename):
url = makeurl(['source', prj, package, filename])
f = urllib2.urlopen(url)
@ -319,6 +597,26 @@ def get_source_file_diff(prj, package, filename):
return ''.join(d)
def get_source_file_diff(dir, filename, rev):
import difflib
file1 = os.path.join(dir, filename)
file2 = os.path.join(dir, store, filename)
f1 = open(file1, 'r')
f2 = open(file2, 'r')
d = difflib.unified_diff(\
f1.readlines(), \
f2.readlines(), \
fromfile = '%s (revision %s)' % (filename, rev), \
tofile = '%s (working copy)' % filename)
f1.close()
f2.close()
return ''.join(d)
def put_source_file(prj, package, filename):
import othermethods
@ -341,13 +639,17 @@ def del_source_file(prj, package, filename):
def make_dir(project, package):
#print "creating directory '%s'" % project
print 'A %s' % project
print statfrmt('A', project)
if not os.path.exists(project):
os.mkdir(project)
os.mkdir(os.path.join(project, store))
f = open(os.path.join(project, store, '_project'), 'w')
f.write(project + '\n')
f.close()
#print "creating directory '%s/%s'" % (project, package)
print 'A %s/%s' % (project, package)
print statfrmt('A', '%s/%s' % (project, package))
if not os.path.exists(os.path.join(project, package)):
os.mkdir(os.path.join(project, package))
os.mkdir(os.path.join(project, package, store))
@ -435,6 +737,15 @@ def get_log(prj, package, platform, arch):
return f.readlines()
def get_history(prj, package):
# http://api.opensuse.org/rpm/Apache/factory/i586/apache2/history ?
# http://api.opensuse.org/package/Apache/apache2/history ?
u = makeurl(['package', prj, package, 'history'])
print u
f = urllib2.urlopen(u)
return f.readlines()
def store_read_project(dir):
p = open(os.path.join(dir, store, '_project')).readlines()[0].strip()
return p

View File

@ -3,7 +3,7 @@
from distutils.core import setup
setup(name='osc',
version='0.2',
version='0.3',
description='opensuse commander',
author='Peter Poeml',
author_email='poeml@suse.de',