def get_branch_from_sandbox(self, dir): rc, lines = self.process.popen('git branch', echo=False) if rc == 0: for line in lines: if line.startswith('*'): return line[2:] err_exit('Failed to get branch from %(dir)s' % locals())
def run_register(self, dir, infoflags, location, ff='', quiet=False): if not self.process.quiet: print 'running register' echo = After('running register') if quiet: echo = And(echo, Not(Equals(OK_RESPONSE))) checkcmd = [] if 'check' in distutils.command.__all__: checkcmd = ['check'] serverflags = ['--repository="%(location)s"' % locals()] rc, lines = self._run_setup_py( ['egg_info'] + infoflags + checkcmd + ['register'] + serverflags, echo=echo, ff=ff) if rc == 0: if self._parse_register_results(lines): if not self.process.quiet and quiet: print 'OK' return rc err_exit('ERROR: register failed')
def run_sftp(self, distfile, location): if not self.process.quiet: print 'running sftp_upload' self.delay() name = basename(distfile) print 'Uploading dist/%(name)s to %(location)s' % locals() with tempfile.NamedTemporaryFile() as file: cmds = 'put "%(distfile)s"\nbye\n' % locals() if sys.version_info[0] >= 3: cmds = encode(cmds) file.write(cmds) file.flush() cmdfile = file.name try: rc, lines = self.process.popen( 'sftp -b "%(cmdfile)s" "%(location)s"' % locals(), echo=False) if rc == 0: if not self.process.quiet: print 'OK' return rc except KeyboardInterrupt: pass err_exit('ERROR: sftp failed')
def get_package_info(self, dir): python = self.python rc, lines = self.process.popen( '"%(python)s" setup.py --name --version' % locals(), echo=False) if rc == 0 and len(lines) > 1: return lines[0], lines[1] err_exit('Bad setup.py')
def get_options(self): """Process the command line. """ args = self.parse_options(self.args) if args: self.directory = args[0] if self.list: self.list_locations() if not self.locations: self.locations.extend(self.locations.get_default_location()) if not self.skipupload: self.locations.check_valid_locations() if len(args) > 1: if self.urlparser.is_url(self.directory): self.branch = args[1] elif self.urlparser.is_ssh_url(self.directory): self.branch = args[1] else: err_exit('mkrelease: too many arguments\n%s' % USAGE) if len(args) > 2: err_exit('mkrelease: too many arguments\n%s' % USAGE)
def create_tag(self, dir, tagid, name, version, push): url = self.get_url_from_sandbox(dir) rc = self.process.system( 'svn copy -m"Tagged %(name)s %(version)s." "%(url)s" "%(tagid)s"' % locals()) if rc != 0: err_exit('Tag failed') return rc
def switch_branch(self, dir, branch): if branch != self.get_branch_from_sandbox(dir): rc = self.process.system( 'hg update "%(branch)s"' % locals()) if rc != 0: err_exit('Update failed') return 0
def switch_branch(self, dir, branch): if branch != self.get_branch_from_sandbox(dir): rc = self.process.system( 'git checkout -q "%(branch)s"' % locals()) if rc != 0: err_exit('Checkout failed') return 0
def commit_sandbox(self, dir, name, version, push): rc = self.process.system( 'svn commit -m"Prepare %(name)s %(version)s." "%(dir)s"' % locals()) if rc != 0: err_exit('Commit failed') return rc
def run_scp(self, distfile, location): if not self.process.quiet: print 'running scp' rc = self.process.os_system( 'scp "%(distfile)s" "%(location)s"' % locals()) if rc != 0: err_exit('scp failed') return rc
def create_tag(self, dir, tagid, name, version, push): url = self.get_url_from_sandbox(dir) rc, lines = self.process.popen( ('svn copy -m"Tagged %(name)s %(version)s." "%(url)s" "%(tagid)s"' % locals()), echo=tee.NotEmpty()) if rc != 0: err_exit('Tag failed') return rc
def get_branch_from_sandbox(self, dir): rc, lines = self.process.popen( 'git branch', echo=False) if rc == 0: for line in lines: if line.startswith('*'): return line[2:] err_exit('Failed to get branch from %(dir)s' % locals())
def tag_exists(self, dir, tagid): rc, lines = self.process.popen('git tag', echo=False) if rc == 0: for line in lines: if line == tagid: return True return False err_exit('Failed to get tags from %(dir)s' % locals())
def get_url_from_sandbox(self, dir): rc, lines = self.process.popen( 'svn info "%(dir)s"' % locals(), echo=False) if rc == 0 and lines: if self.version_info[:2] >= (1, 7): return lines[2][5:] else: return lines[1][5:] err_exit('Failed to get URL from %(dir)s' % locals())
def tag_exists(self, dir, tagid): rc, lines = self.process.popen( 'git tag', echo=False) if rc == 0: for line in lines: if line == tagid: return True return False err_exit('Failed to get tags from %(dir)s' % locals())
def get_root_from_sandbox(self, dir): rc, lines = self.process.popen( 'svn info "%(dir)s"' % locals(), echo=False) if rc == 0 and lines: url = lines[1][5:] if not self.is_same_sandbox(dirname(dir), url): return dir return self.get_root_from_sandbox(dirname(dir)) err_exit('Failed to get root from %(dir)s' % locals())
def get_url_from_sandbox(self, dir): rc, lines = self.process.popen('svn info "%(dir)s"' % locals(), echo=False) if rc == 0 and lines: if self.version_info[:2] >= (1, 7): return lines[2][5:] else: return lines[1][5:] err_exit('Failed to get URL from %(dir)s' % locals())
def tag_exists(self, dir, tagid): url, version = tagid.rsplit('/', 1) rc, lines = self.process.popen('svn list "%(url)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[:-1] == version: return True return False err_exit('Failed to get tags from %(url)s' % locals())
def get_url_from_sandbox(self, dir): self.get_branch_from_sandbox(dir) # Called here for its error checking only rc, lines = self.process.popen( 'hg show paths.default', echo=False) if rc == 0: if lines: return lines[0] else: err_exit('Failed to get URL from %(dir)s' % locals()) return ''
def get_base_url_from_sandbox(self, dir): url = self.get_url_from_sandbox(dir) parts = url.split('/') for i in reversed(range(len(parts))): if parts[i] in ('trunk', 'branches', 'tags', 'branch', 'tag'): parts = parts[:i] break else: err_exit('Failed to get layout from %(url)s' % locals()) return '/'.join(parts)
def tag_exists(self, dir, tagid): url, version = tagid.rsplit('/', 1) rc, lines = self.process.popen( 'svn list "%(url)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[:-1] == version: return True return False err_exit('Failed to get tags from %(url)s' % locals())
def get_url_from_sandbox(self, dir): self.get_branch_from_sandbox( dir) # Called here for its error checking only rc, lines = self.process.popen('hg show paths.default', echo=False) if rc == 0: if lines: return lines[0] else: err_exit('Failed to get URL from %(dir)s' % locals()) return ''
def check_valid_locations(self, locations=None): """Fail if 'locations' is empty or contains bad scp destinations. """ if locations is None: locations = self.locations if not locations: err_exit('mkrelease: option -d is required\n%s' % USAGE) for location in locations: if not self.is_server(location) and not self.has_host(location): err_exit('Scp destination must contain a host part: %(location)s' % locals())
def get_tracked_branch_from_sandbox(self, dir): branch = self.get_branch_from_sandbox(dir) rc, lines = self.process.popen('git config -l', echo=False) if rc == 0 and lines: key = 'branch.%(branch)s.merge=' % locals() for line in reversed(lines): if line.startswith(key): return line[len(key) + len('refs/heads/'):] else: err_exit('Failed to get tracked branch from %(branch)s' % locals()) return ''
def get_layout_from_sandbox(self, dir): url = self.get_base_url_from_sandbox(dir) rc, lines = self.process.popen( 'svn list "%(url)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[:-1] == 'tag': return ('trunk', 'branch', 'tag') if line[:-1] == 'tags': return ('trunk', 'branches', 'tags') err_exit('No tags directory found in %(url)s' % locals())
def make_tagid(self, dir, version): url = self.get_url_from_sandbox(dir) parts = url.split('/') if parts[-1] == 'trunk': parts = parts[:-1] elif parts[-2] in ('branches', 'tags', 'branch', 'tag'): parts = parts[:-2] else: err_exit('URL must point to trunk, branch, or tag: %(url)s' % locals()) layout = self.get_layout_from_sandbox(dir) return '/'.join(parts + [layout[2], version])
def is_dirty_sandbox(self, dir): rc, lines = self.process.popen('svn status "%(dir)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[0:1] in ('M', 'A', 'R', 'D'): return True if line[1:2] in ('M', ): return True return False err_exit('Failed to get status from %(dir)s' % locals())
def create_tag(self, dir, tagid, name, version, push): rc = self.process.system( 'hg tag -m"Tagged %(name)s %(version)s." "%(tagid)s"' % locals()) if rc != 0: err_exit('Tag failed') if push and self.is_remote_sandbox(dir): rc = self.process.system( 'hg push') if rc != 0: err_exit('Push failed') return rc
def get_layout_from_sandbox(self, dir): url = self.get_base_url_from_sandbox(dir) rc, lines = self.process.popen('svn list "%(url)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[:-1] == 'tag': return ('trunk', 'branch', 'tag') if line[:-1] == 'tags': return ('trunk', 'branches', 'tags') err_exit('No tags directory found in %(url)s' % locals())
def is_dirty_sandbox(self, dir): rc, lines = self.process.popen( 'svn status "%(dir)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[0:1] in ('M', 'A', 'R', 'D'): return True if line[1:2] in ('M',): return True return False err_exit('Failed to get status from %(dir)s' % locals())
def parse_options(self, args): """Parse command line options. """ try: options, args = getopt.gnu_getopt(args, 'CSTbd:ehi:lnpqsv', ('no-commit', 'no-tag', 'no-upload', 'dry-run', 'sign', 'identity=', 'dist-location=', 'version', 'help', 'push', 'quiet', 'svn', 'hg', 'git', 'develop', 'binary', 'list-locations')) except getopt.GetoptError, e: err_exit('mkrelease: %s\n%s' % (e.msg, USAGE))
def check_valid_locations(self, locations=None): """Fail if 'locations' is empty or contains bad destinations. """ if locations is None: locations = self.locations if not locations: err_exit('mkrelease: option -d is required\n%s' % USAGE) for location in locations: if (not self.is_server(location) and not self.is_dist_url(location) and not self.has_host(location)): err_exit('Unknown location: %(location)s' % locals())
def get_package_info(self, dir, develop=False): python = self.python rc, lines = self.process.popen( '"%(python)s" setup.py --name --version' % locals(), echo=False) if rc == 0 and len(lines) == 2: name, version = lines if develop: parser = ConfigParser(warn) parser.read('setup.cfg') version += parser.get('egg_info', 'tag_build', '').strip() return name, pkg_resources.safe_version(version) err_exit('Bad setup.py')
def get_url_from_sandbox(self, dir): remote = self.get_remote_from_sandbox(dir) if remote: rc, lines = self.process.popen('git config -l', echo=False) if rc == 0 and lines: key = 'remote.%(remote)s.url=' % locals() for line in reversed(lines): if line.startswith(key): return line[len(key):] else: err_exit('Failed to get URL from %(dir)s' % locals()) return ''
def checkin_sandbox(self, dir, name, version, push): rc = self.process.system( 'hg commit -v -m"Prepare %(name)s %(version)s." .' % locals()) if rc not in (0, 1): err_exit('Commit failed') rc = 0 if push and self.is_remote_sandbox(dir): rc = self.process.system( 'hg push') if rc != 0: err_exit('Push failed') return rc
def get_remote_from_sandbox(self, dir): branch = self.get_branch_from_sandbox(dir) rc, lines = self.process.popen( 'git config -l', echo=False) if rc == 0 and lines: key = 'branch.%(branch)s.remote=' % locals() for line in lines: if line.startswith(key): return line[len(key):] else: err_exit('Failed to get remote from %(dir)s' % locals()) return ''
def get_tracked_branch_from_sandbox(self, dir): branch = self.get_branch_from_sandbox(dir) rc, lines = self.process.popen( 'git config -l', echo=False) if rc == 0 and lines: key = 'branch.%(branch)s.merge=' % locals() for line in lines: if line.startswith(key): return line[len(key):][len('refs/heads/'):] else: err_exit('Failed to get tracked branch from %(dir)s' % locals()) return ''
def get_root_from_sandbox(self, dir): rc, lines = self.process.popen('svn info "%(dir)s"' % locals(), echo=False) if rc == 0 and lines: if self.version_info[:2] >= (1, 7): url = lines[2][5:] else: url = lines[1][5:] if not self.is_same_sandbox(dirname(dir), url): return dir return self.get_root_from_sandbox(dirname(dir)) err_exit('Failed to get root from %(dir)s' % locals())
def get_url_from_sandbox(self, dir): remote = self.get_remote_from_sandbox(dir) if remote: rc, lines = self.process.popen( 'git config -l', echo=False) if rc == 0 and lines: key = 'remote.%(remote)s.url=' % locals() for line in lines: if line.startswith(key): return line[len(key):] else: err_exit('Failed to get URL from %(dir)s' % locals()) return ''
def create_tag(self, dir, tagid, name, version, push): rc = self.process.system( 'hg tag -m"Tagged %(name)s %(version)s." "%(tagid)s"' % locals()) if rc != 0: err_exit('Tag failed') if push: if self.is_remote_sandbox(dir): rc = self.process.system('hg push default') if rc != 0: err_exit('Push failed') else: warn('No default path found; not pushing the tag') return rc
def is_dirty_sandbox(self, dir): if self.version_info[:2] >= (1, 7): rc, lines = self.process.popen( 'git status --porcelain --untracked-files=no .', echo=False) if rc == 0: return bool(lines) else: rc, lines = self.process.popen('git status .', echo=False) if rc == 0: return True if rc == 1: return False err_exit('Failed to get status from %(dir)s' % locals())
def create_tag(self, dir, tagid, name, version, push): rc = self.process.system( 'hg tag -m"Tagged %(name)s %(version)s." "%(tagid)s"' % locals()) if rc != 0: err_exit('Tag failed') if push: if self.is_remote_sandbox(dir): rc = self.process.system( 'hg push default') if rc != 0: err_exit('Push failed') else: warn('No default path found; not pushing the tag') return rc
def is_unclean_sandbox(self, dir): rc, lines = self.process.popen('svn status "%(dir)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[0:1] in ('M', 'A', 'R', 'D', 'C', '!', '~'): return True if line[1:2] in ('M', 'C'): return True if self.version_info[:2] >= (1, 6): if line[6:7] in ('C', ): return True return False err_exit('Failed to get status from %(dir)s' % locals())
def is_unclean_sandbox(self, dir): rc, lines = self.process.popen( 'svn status "%(dir)s"' % locals(), echo=False) if rc == 0: for line in lines: if line[0:1] in ('M', 'A', 'R', 'D', 'C', '!', '~'): return True if line[1:2] in ('M', 'C'): return True if self.version_info[:2] >= (1, 6): if line[6:7] in ('C',): return True return False err_exit('Failed to get status from %(dir)s' % locals())
def is_dirty_sandbox(self, dir): if self.version_info[:2] >= (1, 7): rc, lines = self.process.popen( 'git status --porcelain --untracked-files=no .', echo=False) if rc == 0: return bool(lines) else: rc, lines = self.process.popen( 'git status .', echo=False) if rc == 0: return True if rc == 1: return False err_exit('Failed to get status from %(dir)s' % locals())
def run_egg_info(self, dir, infoflags, ff='', quiet=False): if not self.process.quiet: print 'running egg_info' echo = After('running egg_info') if quiet: echo = And(echo, StartsWith('running')) rc, lines = self._run_setup_py(['egg_info'] + infoflags, echo=echo, ff=ff) if rc == 0: filename = self._parse_egg_info_results(lines) if filename and isfile(filename): return abspath(filename) err_exit('egg_info failed')
def run_scp(self, distfile, location): if not self.process.quiet: print 'running scp_upload' self.delay() name = basename(distfile) print 'Uploading dist/%(name)s to %(location)s' % locals() try: rc, lines = self.process.popen( 'scp "%(distfile)s" "%(location)s"' % locals(), echo=False) if rc == 0: if not self.process.quiet: print 'OK' return rc except KeyboardInterrupt: pass err_exit('ERROR: scp failed')
def create_tag(self, dir, tagid, name, version, push): rc = self.process.system( 'git tag -m"Tagged %(name)s %(version)s." "%(tagid)s"' % locals()) if rc != 0: err_exit('Tag failed') if push: branch = self.get_branch_from_sandbox(dir) remote = self.get_remote_from_sandbox(dir) if remote: tracked = self.get_tracked_branch_from_sandbox(dir) if tracked: rc = self.process.system( 'git push "%(remote)s" tag "%(tagid)s"' % locals()) if rc != 0: err_exit('Push failed') return rc warn('%(branch)s does not track a remote branch; ' 'not pushing the tag' % locals()) return rc
def commit_sandbox(self, dir, name, version, push): rc = self.process.system( 'git commit -m"Prepare %(name)s %(version)s." .' % locals()) if rc not in (0, 1): err_exit('Commit failed') rc = 0 if push: branch = self.get_branch_from_sandbox(dir) remote = self.get_remote_from_sandbox(dir) if remote: tracked = self.get_tracked_branch_from_sandbox(dir) if tracked: rc = self.process.system( 'git push "%(remote)s" "%(branch)s:%(tracked)s"' % locals()) if rc != 0: err_exit('Push failed') return rc warn('%(branch)s does not track a remote branch; ' 'not pushing the commit' % locals()) return rc
def get_location(self, location, depth=0): """Resolve aliases and apply distbase. """ if not location: return [] if location in self.aliases: res = [] if depth > MAXALIASDEPTH: err_exit('Maximum alias depth exceeded: %(location)s' % locals()) for loc in self.aliases[location]: res.extend(self.get_location(loc, depth+1)) return res if self.is_server(location): return [location] if location == 'pypi': err_exit('No configuration found for server: pypi\n' 'Please create a ~/.pypirc file') if self.urlparser.is_url(location): return [location] if not self.has_host(location) and self.distbase: return [self.join(self.distbase, location)] return [location]
def check_valid_file(self, file): """Check if 'file' can be read. """ if not exists(file): err_exit('No such file: %(file)s' % locals()) if not isfile(file): err_exit('Not a file: %(file)s' % locals()) if not os.access(file, os.R_OK): err_exit('File cannot be read: %(file)s' % locals())
def run_sftp(self, distfile, location): if not self.process.quiet: print 'running sftp_upload' self.delay() name = basename(distfile) print 'Uploading dist/%(name)s to %(location)s' % locals() with tempfile.NamedTemporaryFile() as file: file.write('put "%(distfile)s"\n' % locals()) file.write('bye\n') file.flush() cmdfile = file.name try: rc, lines = self.process.popen( 'sftp -b "%(cmdfile)s" "%(location)s"' % locals(), echo=False) if rc == 0: if not self.process.quiet: print 'OK' return rc except KeyboardInterrupt: pass err_exit('ERROR: sftp failed')
def get_scm_from_url(self, url): scheme, user, host, path, qs, frag = self.urlparser.urlsplit(url) if scheme in ('svn', 'svn+ssh'): return Subversion() if scheme in ('git', 'rsync'): return Git() if scheme in ('ssh', ): if path.endswith('.git'): return Git() if host.startswith('hg.') or path.startswith(('/hg/', '//hg/')): return Mercurial() if host.startswith('git.') or path.startswith('/git/'): return Git() if user == 'git' or host == 'github.com': return Git() err_exit('Failed to guess SCM type: %(url)s\n' 'Please specify --svn, --hg, or --git' % locals()) if scheme in ('http', 'https'): if path.endswith('.git'): return Git() if host.startswith('svn.') or path.startswith('/svn/'): return Subversion() if host.startswith('hg.') or path.startswith('/hg/'): return Mercurial() if host.startswith('git.') or path.startswith('/git/'): return Git() if user == 'git' or host == 'github.com': return Git() err_exit('Failed to guess SCM type: %(url)s\n' 'Please specify --svn, --hg, or --git' % locals()) if scheme in ('file', ): if path.endswith('.git'): return Git() if host in ('', 'localhost'): # Strip leading slash to allow tilde expansion if host and path.startswith('/~'): path = path[1:] if self._is_bare_git_repo(path): return Git() if self._is_subversion_repo(path): return Subversion() return self._get_scm_from_file_url(path) err_exit('Failed to guess SCM type: %(url)s\n' 'Please specify --svn, --hg, or --git' % locals()) err_exit('Unsupported URL scheme: %(scheme)s' % locals())
def _get_scm_from_file_url(self, dir): # Return clonable repository roots only dir = abspath(expanduser(dir)) if not exists(dir): err_exit('No such file or directory: %(dir)s' % locals()) matches = self._find_scms(dir) matches = self._find_clonable(dir, matches) if not matches: err_exit('Not a repository: %(dir)s' % locals()) matches = self._find_roots(dir, matches) if not matches: err_exit('Not a repository root: %(dir)s' % locals()) if len(matches) == 1: return matches[0] if len(matches) == 2: names = '%s and %s' % tuple( [x.__class__.__name__ for x in matches]) flags = '--%s or --%s' % tuple([x.name for x in matches]) err_exit('%(names)s found in %(dir)s\n' 'Please specify %(flags)s to resolve' % locals())
def commit_sandbox(self, dir, name, version, push): rc = self.process.system( 'hg commit -v -m"Prepare %(name)s %(version)s." .' % locals()) if rc not in (0, 1): # 1 means empty commit err_exit('Commit failed') rc = 0 if push: if self.is_remote_sandbox(dir): rc = self.process.system('hg push default') if self.version_info[:2] >= (2, 1): if rc not in (0, 1): # 1 means empty push err_exit('Push failed') rc = 0 else: if rc != 0: err_exit('Push failed') else: warn('No default path found; not pushing the commit') return rc
def get_scm_from_sandbox(self, dir): dir = abspath(expanduser(dir)) if not exists(dir): err_exit('No such file or directory: %(dir)s' % locals()) matches = self._find_scms(dir) if not matches: err_exit('Not a sandbox: %(dir)s' % locals()) if len(matches) == 1: return matches[0] matches = self._find_closest(dir, matches) if len(matches) == 1: return matches[0] if len(matches) == 2: names = '%s and %s' % tuple( [x.__class__.__name__ for x in matches]) flags = '--%s or --%s' % tuple([x.name for x in matches]) elif len(matches) == 3: names = '%s, %s, and %s' % tuple( [x.__class__.__name__ for x in matches]) flags = '--%s, --%s, or --%s' % tuple([x.name for x in matches]) err_exit('%(names)s found in %(dir)s\n' 'Please specify %(flags)s to resolve' % locals())
def check_valid_sandbox(self, dir): if not exists(dir): err_exit('No such file or directory: %(dir)s' % locals()) if not self.is_valid_sandbox(dir): name = self.__class__.__name__ err_exit('Not a %(name)s sandbox: %(dir)s' % locals())