Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/misc/hg.py
4057 views
1
r"""
2
Sage Interface to the HG/Mercurial Revision Control System
3
4
These functions make setup and use of source control with Sage
5
easier, using the distributed Mercurial HG source control system.
6
To learn about Mercurial, see
7
http://www.selenic.com/mercurial/wiki/, in particular
8
http://mercurial.selenic.com/wiki/UnderstandingMercurial.
9
See also the `Sage Developer's Guide
10
<http://www.sagemath.org/doc/developer/>`_ and
11
http://wiki.sagemath.org/MercurialQueues for information about using
12
Mercurial with Sage.
13
14
Some useful commands:
15
16
- Use ``hg_sage.diff()`` to view any changes made to the repository.
17
18
- Use ``hg_sage.log()`` to see the change log for the repository.
19
20
- Use ``hg_sage.serve()`` to start a web server for examining the
21
repository.
22
23
- Use ``hg_sage.commit()`` or ``hg_sage.record()`` to record any
24
changes you've made to the repository.
25
26
- Use ``hg_sage.export('tip')`` to produce a patch file for posting
27
to the Sage trac server.
28
29
- Use ``hg_sage.import_patch('file.patch')`` to import the Mercurial
30
patch file ``file.patch``.
31
32
- Use ``hg_sage.revert('file', rev=1234)`` reverts ``file`` to the
33
contents it had in revision 1234.
34
35
- Use ``hg_sage.rollback()`` to remove recorded patches without
36
changing the working copy.
37
38
- Use ``hg_sage.pull()`` to synchronize with the
39
latest official stable Sage changesets.
40
41
If you want to use Mercurial queues, then type ``hg_sage.q[TAB]`` to
42
see the list of available methods. Indeed, many Mercurial commands
43
are provided by methods here -- type ``hg_sage.[TAB]`` to get a full
44
list -- and you can execute any Mercurial command using
45
``hg_sage(COMMAND)``. Finally, as listed, the above commands deal with
46
the Mercurial repository for the Sage library. If you want to work
47
with other repositories distributed with Sage, this file provides the
48
following -- replace "hg_sage" with each of the following commands to
49
work with the given repository:
50
51
- ``hg_scripts`` -- the scripts repository (files in
52
:file:`SAGE_ROOT/local/bin`)
53
54
- ``hg_sagenb`` -- the Sage notebook repository (files in
55
:file:`SAGE_ROOT/devel/sagenb`)
56
57
- ``hg_root`` -- the Sage root repository (including files in
58
:file:`SAGE_ROOT` and :file:`SAGE_ROOT/spkg`)
59
60
- ``hg_extcode`` -- the extcode repository (files in
61
:file:`SAGE_ROOT/data/extcode`)
62
"""
63
64
########################################################################
65
# Copyright (C) 2006 William Stein <[email protected]>
66
# 2007 Jonathan Hanke <[email protected]>
67
#
68
# Distributed under the terms of the GNU General Public License (GPL)
69
#
70
# http://www.gnu.org/licenses/
71
########################################################################
72
73
import os, shutil
74
75
from viewer import browser
76
from misc import tmp_filename, branch_current_hg, embedded
77
from remote_file import get_remote_file as get_remote_file0
78
from sage.server.misc import print_open_msg
79
from subprocess import Popen
80
import re
81
82
sage_trac_re = re.compile('http[s]?://(sagetrac\.org|trac\.sagemath\.org)/sage_trac/attachment/ticket/[0-9]+/.*\.(patch|hg)')
83
84
def get_remote_file(f, **kwds):
85
"""
86
Wrap the get_remote_file method to move the file if it ends in
87
?stuff, as happens with funny URLs from web servers.
88
"""
89
g = get_remote_file0(f, **kwds)
90
i = g.find('?')
91
if i >= 0:
92
h = g[:i]
93
os.rename(g,h)
94
return h
95
return g
96
97
def pager():
98
r"""
99
Return a pager program, either 'cat' or 'less':
100
'cat' if embedded in the notebook, 'less' otherwise.
101
102
It is returned as a string suitable for a config option for the
103
'hg' command.
104
105
EXAMPLES::
106
107
sage: sage.server.support.EMBEDDED_MODE=False
108
sage: sage.misc.hg.pager()
109
'--config pager.pager="LESS=\'R\' less"'
110
sage: sage.server.support.EMBEDDED_MODE=True
111
sage: sage.misc.hg.pager()
112
'--config pager.pager=cat'
113
sage: sage.server.support.EMBEDDED_MODE=False
114
"""
115
if embedded():
116
return '--config pager.pager=cat'
117
else:
118
return '--config pager.pager="LESS=\'R\' less"'
119
120
def color():
121
"""
122
Color option for Mercurial.
123
124
This is empty when called from the command-line, and it disables
125
the "color" extension when called from the notebook. According
126
to the Mercurial docs, "color" is only used by the Mercurial
127
commands diff, status, and qseries; however, it also seems to be
128
used by a few other commands (like log, and qapplied, among
129
others). This function is used in :meth:`HG.diff`,
130
:meth:`HG.log`, :meth:`HG.status`, :meth:`HG.qdiff`,
131
:meth:`HG.qseries`, :meth:`HG.qapplied`, and
132
:meth:`HG.qunapplied`.
133
134
EXAMPLES::
135
136
sage: sage.server.support.EMBEDDED_MODE=False
137
sage: sage.misc.hg.color()
138
''
139
sage: sage.server.support.EMBEDDED_MODE=True
140
sage: sage.misc.hg.color()
141
'--config color.mode=off'
142
sage: sage.server.support.EMBEDDED_MODE=False
143
"""
144
if embedded():
145
return '--config color.mode=off'
146
else:
147
return ''
148
149
hg_docstring = r"""
150
This is an HG (Mercurial) repository.
151
152
To learn about Mercurial, see http://www.selenic.com/mercurial/wiki/.
153
154
This system is fully usable from both the command line and the Sage notebook.
155
156
Most commands are directly provided as member functions. However,
157
you can use the full functionality of hg, i.e.,
158
159
``hg_%(obj_name)s("command line arguments")``
160
161
is *exactly* the same as typing::
162
163
cd %(dir)s && hg command line arguments
164
165
"""
166
167
168
class HG:
169
def __init__(self, dir, name, pull_url, push_url, target=None, cloneable=False, obj_name=''):
170
"""
171
INPUT:
172
173
- ``dir`` - directory that will contain the repository
174
175
- ``name`` - a friendly name for the repository (only used for
176
printing)
177
178
- ``pull_url`` - a default URL to pull or record sends against
179
(e.g., this could be a master repository on
180
modular.math.washington.edu)
181
182
- ``push_url`` - a default URL to push or record outgoing
183
changes against (e.g., this could be a local repository on
184
your favorite computer)
185
186
- ``target`` - if the last part of dir is, e.g., sage-hg,
187
create a symlink from sage-hg to target. If target=None,
188
this symlink will not be created.
189
190
TESTS::
191
192
sage: 'scripts' in hg_scripts.__doc__
193
True
194
"""
195
self.__dir = os.path.abspath(dir)
196
self.__name = name
197
self.__pull_url = pull_url
198
self.__push_url = push_url
199
self.__initialized = False
200
self.__target = target
201
self.__cloneable = cloneable
202
self.__obj_name = obj_name
203
204
self.__doc__ = hg_docstring%{'obj_name':obj_name,
205
'dir':self.__dir}
206
207
def __repr__(self):
208
"""
209
EXAMPLES::
210
211
sage: hg_sage
212
Hg repository 'Sage Library Source Code' in directory ...
213
"""
214
return "Hg repository '%s' in directory %s"%(self.__name, self.__dir)
215
216
217
def current_branch(self, print_flag=True):
218
"""
219
Prints the current branch in the main Sage library.
220
221
If ``print_flag`` is True, the default, then print the message
222
"The current branch is NAME". If False, return the string NAME.
223
224
.. warning::
225
226
This prints the current branch for the main Sage library
227
repository, even if you call a command like
228
"hg_scripts.current_branch()" which refers to a different
229
repository.
230
231
EXAMPLES::
232
233
sage: hg_sage.current_branch()
234
The current branch is: ...
235
"""
236
branch_name = branch_current_hg()
237
if print_flag:
238
print "The current branch is: " + branch_name
239
else:
240
return branch_name
241
242
def list_branches(self, print_flag=True):
243
"""
244
Print all branches in the current Sage installation.
245
246
If ``print_flag`` is True, the default, then print the message
247
"Branches found:", followed by a list of the branches. If
248
False, return the list of the names of the branches.
249
250
.. warning::
251
252
This lists the branches for the main Sage library
253
repository, even if you call a command like
254
"hg_scripts.list_branches()" which refers to a different
255
repository.
256
257
EXAMPLES::
258
259
sage: hg_sage.list_branches()
260
Branches found:
261
...
262
sage: 'main' in hg_sage.list_branches(print_flag=False)
263
True
264
"""
265
try:
266
tmp_branch_list = [s[5:] for s in os.listdir(SAGE_ROOT + "/devel") if s.startswith("sage-")]
267
except:
268
raise RuntimeError, "Oops! We had trouble... Check that SAGE_ROOT gives the correct directory."
269
270
if print_flag:
271
print "Branches found:"
272
for s in tmp_branch_list:
273
print " " + s
274
else:
275
return tmp_branch_list
276
277
278
def status(self, debug=True):
279
"""
280
Print the output of the command "hg status" for the repository.
281
282
If ``debug`` is True, also print the full system command being
283
executed.
284
285
EXAMPLES::
286
287
sage: hg_sage.status()
288
Getting status of modified or unknown files:
289
cd ... && sage --hg status
290
...
291
sage: hg_sage.status(debug=False)
292
Getting status of modified or unknown files:
293
...
294
"""
295
print("Getting status of modified or unknown files:")
296
self('status %s' % (color(),), debug=debug)
297
print "\n---\n"
298
if self.__name == "Sage Library Source Code":
299
b = branch_current_hg()
300
if b == '': b='main'
301
elif b[-1] == '/':
302
b = b[:-1]
303
print("Branch: %s"%b)
304
305
def _changed_files(self):
306
"""
307
EXAMPLES::
308
309
sage: hg_sage._changed_files() # random
310
False
311
"""
312
out, err = self('status', interactive=False, debug=False)
313
v = [x for x in out.split('\n') if (x.strip()[:1] != '?' and x.strip()[:1] != '!') and len(x) != 0]
314
return len(v) > 0
315
316
def _ensure_safe(self):
317
"""
318
Ensure that the repository is in a safe state to have changes
319
applied to it, i.e., that all changes to controlled files in the
320
working directory are recorded.
321
322
EXAMPLES:
323
324
sage: hg_sage._ensure_safe() # not tested
325
"""
326
if self._changed_files():
327
self.ci()
328
if self._changed_files():
329
raise RuntimeError, "Refusing to do operation since you still have unrecorded changes. You must check in all changes in your working repository first."
330
331
def _warning(self):
332
"""
333
Print a warning if the user has no .hgrc file.
334
335
EXAMPLES::
336
337
sage: hg_sage._warning() # random
338
"""
339
from sage.plot.plot import DOCTEST_MODE
340
if not os.path.exists(os.path.join(os.environ['HOME'], '.hgrc')) and not DOCTEST_MODE:
341
print "\nWARNING:"
342
print "Make sure to create a ~/.hgrc file:"
343
print "-"*70
344
print "[ui]"
345
print "username = William Stein <[email protected]>"
346
print "-"*70
347
print "\n"
348
349
def __call__(self, cmd=None, interactive=True, debug=True):
350
"""
351
Run 'hg cmd' where cmd is an arbitrary string in the hg
352
repository.
353
354
INPUT:
355
356
- ``cmd`` - string, the hg command line (everything
357
after 'hg')
358
359
- ``interactive`` - If True, runs using os.system, so
360
user can interactively interact with hg, i.e., this is needed when
361
you record changes because the editor pops up. If False, Popen is
362
used to launch hg as a subprocess.
363
364
- ``debug`` - if True, print the full system command being
365
executed.
366
367
OUTPUT:
368
369
- If interactive is True, returns the exit code of the
370
system call.
371
372
- If interactive is False, returns the output and
373
error text.
374
375
- If cmd is not supplied, returns the output of the
376
'status' command
377
378
EXAMPLES::
379
380
sage: hg_sage('hello') # not tested
381
hg: unknown command 'hello'
382
...
383
sage: hg_sage('status') # not tested
384
...
385
"""
386
self._warning()
387
if cmd is None:
388
cmd = 'status'
389
# Invoke Mercurial with "sage --hg", not just "hg": when
390
# calling "hg", the variable HGPLAIN is set (by sage-env),
391
# which disables various configuration options, like the use
392
# of a pager. When calling "sage --hg", HGPLAIN is explicitly
393
# unset (see the script sage-sage), so the pager will be used,
394
# as will color output, etc. See trac ticket #12288.
395
s = 'cd "%s" && sage --hg %s'%(self.__dir, cmd)
396
if debug:
397
print s
398
if interactive:
399
e = os.system(s)
400
return e
401
else:
402
from subprocess import PIPE
403
x = Popen(s, shell=True,
404
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
405
x.stdin.close()
406
out = x.stdout.read()
407
err = x.stderr.read()
408
return out, err
409
410
def serve(self, port=8200, address='localhost',
411
open_viewer=True, options='', debug=True):
412
"""
413
Start a web server for this repository.
414
415
This server allows you to browse all files in the repository,
416
see their changelogs, see who wrote any given line, etc.
417
418
INPUT:
419
420
- ``port`` - port that the server will listen on
421
422
- ``address`` - (default: 'localhost') address to
423
listen on
424
425
- ``open_viewer`` - boolean (default: True); whether
426
to pop up the web page
427
428
- ``options`` - a string passed directly to hg's serve
429
command.
430
431
- ``debug`` - boolean (default True); if True, print the full
432
system command being executed.
433
434
EXAMPLES::
435
436
sage: hg_sage.serve() # not tested
437
"""
438
if open_viewer:
439
cmd = 'sleep 1; %s http://%s:%s 1>&2 >/dev/null'%(browser(),
440
address, port)
441
t = tmp_filename()
442
open(t,'w').write(cmd)
443
P = os.path.abspath(t)
444
os.system('chmod +x %s; %s &'%(P, P))
445
446
print_open_msg(address, port)
447
self('serve --address %s --port %s %s'%(address, port, options),
448
debug=debug)
449
print_open_msg(address, port)
450
451
browse = serve
452
453
def unbundle(self, bundle, update=True, options='', debug=True):
454
"""
455
Apply patches from a hg patch to the repository.
456
457
If the bundle is a .patch file, instead call the :meth:`import_patch`
458
method. To see what is in a bundle before applying it, using
459
``self.incoming(bundle)``.
460
461
INPUT:
462
463
- ``bundle`` - an hg bundle (created with the bundle
464
command)
465
466
- ``update`` - if True (the default), update the
467
working directory after unbundling.
468
469
- ``debug`` - boolean (default True); if True, print the full
470
system command being executed.
471
472
EXAMPLES::
473
474
sage: hg_sage.unbundle('myhg.bundle') # not tested
475
"""
476
if bundle.startswith("http://") or bundle.startswith("https://"):
477
if sage_trac_re.match(bundle):
478
bundle = bundle.replace('sage_trac/attachment/', 'sage_trac/raw-attachment/')
479
bundle = get_remote_file(bundle, verbose=True)
480
if bundle[-6:] == '.patch':
481
self.import_patch(bundle, options)
482
return
483
if bundle[-5:] == '.diff':
484
return self.import_patch(bundle)
485
self._ensure_safe()
486
bundle = os.path.abspath(bundle)
487
print "Unbundling bundle %s"%bundle
488
if update:
489
options = '-u'
490
else:
491
options = ''
492
493
print "If you get an error 'abort: unknown parent'"
494
print "this usually means either you need to do:"
495
print " hg_%s.pull()"%self.__obj_name
496
print "or you're applying this patch to the wrong repository."
497
self('unbundle %s "%s"'%(options, bundle), debug=debug)
498
499
apply = unbundle
500
501
def export(self, revs, filename=None, text=False, options='', debug=True):
502
r"""
503
Export patches with the changeset header and diffs for one or more
504
revisions.
505
506
If multiple revisions are given, one plain text unified diff file
507
is generated for each one. These files should be applied using
508
import_patch in order from smallest to largest revision number.
509
The information shown in the changeset header is: author, changeset
510
hash, parent and commit comment.
511
512
.. note::
513
514
If you are sending a patch to somebody using export and it
515
depends on previous patches, make sure to include those
516
revisions too! Alternatively, use the :meth:`.bundle`
517
method, which includes enough information to patch against
518
the default repository (but is an annoying and mysterious
519
binary file).
520
521
INPUT:
522
523
- ``revs`` - integer or list of integers (revision
524
numbers); use the log() method to see these numbers.
525
526
- ``filename`` - (default: '%R.patch') The name of the file
527
is given using a format string. The formatting rules are
528
as follows::
529
530
%% literal "%" character
531
%H changeset hash (40 bytes of hexadecimal)
532
%N number of patches being generated
533
%R changeset revision number
534
%b basename of the exporting repository
535
%h short-form changeset hash (12 bytes of hexadecimal)
536
%n zero-padded sequence number, starting at 1
537
%r zero-padded changeset revision number
538
539
- ``text`` - boolean (default False). Setting this to be True
540
has the same effect as passing the "-a" option below.
541
542
- ``options`` - string (default: '')
543
544
- ``'-a'`` or ``'--text'`` - treat all files as text
545
546
- ``'--switch-parent'`` - diff against the second parent
547
548
Without the ``-a`` option, export will avoid generating
549
diffs of files it detects as binary. With ``-a``, export
550
will generate a diff anyway, probably with undesirable
551
results.
552
553
With the ``--switch-parent`` option, the diff will be
554
against the second parent. It can be useful to review a
555
merge.
556
557
- ``debug`` - boolean (default True); if True, print the full
558
system command being executed.
559
560
EXAMPLES::
561
562
sage: hg_sage.export('tip') # not tested
563
sage: hg_sage.export('tip', 'new.patch') # not tested
564
sage: hg_sage.export('tip', 'new.patch', options='--a') # not tested
565
"""
566
if filename is None:
567
filename = '%R.patch'
568
if not isinstance(revs, list):
569
if revs == "tip":
570
revs = [revs]
571
else:
572
revs = [int(revs)]
573
if not isinstance(filename, str):
574
raise TypeError, 'filename must be a string'
575
if filename[-6:] != '.patch':
576
filename += '.patch'
577
full_path = os.path.abspath(filename)
578
cwd = os.path.dirname(full_path)
579
options += ' -o "%s"'%full_path
580
if filename == '%R.patch':
581
print "Output will be written to revision numbered file in the directory %s."%cwd
582
else:
583
print "Output will be written to '%s'"%full_path
584
if text:
585
options += ' -a'
586
self('export %s %s'%(options, ' '.join([str(x) for x in revs])),
587
debug=debug)
588
589
def import_patch(self, filename, options='', debug=True):
590
"""
591
Import an ordered set of patches from patch file, i.e., a plain
592
text file created using the export command.
593
594
If there are outstanding changes in the working directory,
595
import_patch will abort unless given the -f flag.
596
597
If imported patch was generated by the export command, user and
598
description from patch override values from message headers and
599
body. Values given as options with -m and -u override these.
600
601
INPUT:
602
603
- ``filename`` - string
604
605
- ``options`` - string (default: '')::
606
607
options: [-p NUM] [-b BASE] [-m MESSage] [-f] PATCH...
608
609
-p --strip NUM directory strip option for patch. This has
610
the same meaning as the corresponding patch
611
option (default: 1)
612
-b --base PATH base path
613
-f --force skip check for outstanding uncommitted changes
614
--no-commit don't commit, just update the working directory
615
--exact apply patch to the nodes from which it was
616
generated
617
--import-branch use any branch information in patch (implied
618
by --exact)
619
-m --message TEXT use text as commit message
620
-l --logfile FILE read commit message from file
621
-d --date DATE record the specified date as commit date
622
-u --user USER record the specified user as committer
623
-s --similarity SIMILARITY guess renamed files by similarity (0<=s<=100)
624
--mq operate on patch repository
625
626
- ``debug`` - boolean (default True); if True, print the full
627
system command being executed.
628
629
ALIASES: patch
630
631
EXAMPLES::
632
633
sage: hg_sage.import_patch('trac_2001.patch') # not tested
634
"""
635
if filename.startswith("http://") or filename.startswith("https://"):
636
filename = get_remote_file(filename, verbose=True)
637
self._ensure_safe()
638
self('import %s "%s"'%(options, os.path.abspath(filename)),
639
debug=debug)
640
641
patch = import_patch
642
643
def incoming(self, source, options='-p', debug=True):
644
"""
645
Show new changesets found in the given source and display the
646
corresponding diffs. This even works if the source is a bundle file
647
(ends in .hg or .bundle). This is great because it lets you "see
648
inside" the mysterious binary-only .hg files.
649
650
Show new changesets found in the specified path/URL or the default
651
pull location. These are the changesets that would be pulled if a
652
pull was requested.
653
654
For remote repository, using -bundle avoids downloading the
655
changesets twice if the incoming is followed by a pull.
656
657
See pull for valid source format details.
658
659
ALIAS: inspect
660
661
INPUT:
662
663
- ``filename`` - string, may be a URL
664
665
- ``options`` - (default: '-p')::
666
667
string '[-p] [-n] [-M] [-r REV] ...'
668
-M --no-merges do not show merges
669
-f --force run even when remote repository is unrelated
670
--style display using template map file
671
-n --newest-first show newest record first
672
--bundle file to store the bundles into
673
-p --patch show patch
674
-r --rev a specific revision you would like to pull
675
--template display with template
676
-e --ssh specify ssh command to use
677
--remotecmd specify hg command to run on the remote side
678
679
- ``debug`` - boolean (default True); if True, print the full
680
system command being executed.
681
682
EXAMPLES::
683
684
sage: hg_sage.incoming("http://hg.sagemath.org/sage-main") # not tested
685
cd ... && sage --hg incoming "http://hg.sagemath.org/sage-main" --config pager.pager="LESS='R' less"
686
comparing with http://hg.sagemath.org/sage-main
687
searching for changes
688
no changes found
689
"""
690
if source.startswith("http://") or source.startswith("https://"):
691
source = get_remote_file(source, verbose=True)
692
if os.path.exists(source):
693
source = os.path.abspath(source)
694
if os.path.splitext(source)[1] in ['.hg', '.bundle']:
695
source = 'bundle://%s'%source
696
self('incoming %s "%s" %s'%(options, source, pager()), debug=debug)
697
698
inspect = incoming
699
700
701
def add(self, files, options='', debug=True):
702
"""
703
Add the given list of files (or file) or directories to your HG
704
repository. They must exist already.
705
706
To see a list of files that haven't been added to the repository do
707
self.status(). They will appear with an explanation point next
708
them.
709
710
Add needs to be called whenever you add a new file or directory to
711
your project. Of course, it also needs to be called when you first
712
create the project, to let hg know which files should be kept track
713
of.
714
715
INPUT:
716
717
- ``files`` - list or string; name of file or
718
directory.
719
720
- ``options`` - string (e.g., ``'--dry-run'``)
721
722
- ``debug`` - boolean (default True); if True, print the full
723
system command being executed.
724
725
EXAMPLES::
726
727
sage: hg_sage.add('module_list.pyc', options='--dry-run')
728
Adding file module_list.pyc
729
cd ... && sage --hg add --dry-run "module_list.pyc"
730
"""
731
if isinstance(files, str):
732
if ' ' in files:
733
files = files.split()
734
else:
735
files = [files]
736
for file in files:
737
print "Adding file %s"%file
738
self('add %s "%s"'%(options, file), debug=debug)
739
740
def remove(self, files, options='', debug=True):
741
"""
742
Remove the given list of files (or file) or directories from your
743
HG repository.
744
745
INPUT:
746
747
- ``files`` - list or string; name of file or
748
directory.
749
750
- ``options`` - string (e.g., '-f')
751
752
- ``debug`` - boolean (default True); if True, print the full
753
system command being executed.
754
755
EXAMPLES::
756
757
sage: hg_sage.remove('sage/misc/remove_me.py') # not tested
758
Removing file sage/misc/remove_me.py
759
cd ... && sage --hg rm "sage/misc/remove_me.py"
760
"""
761
if isinstance(files, str):
762
files = [files]
763
for file in files:
764
print "Removing file %s"%file
765
self('rm %s "%s"'%(options, file), debug=debug)
766
767
rm = remove
768
769
def rename(self, src, dest, options='', debug=True):
770
"""
771
Move (rename) the given file, from src to dest. This command takes
772
effect in the next commit.
773
774
INPUT:
775
776
- ``src, dest`` - strings that define a file, relative
777
to self.dir()
778
779
- ``options``::
780
781
-A --after record a rename that has already occurred
782
-f --force forcibly copy over an existing managed file
783
-n --dry-run do not perform actions, just print output
784
785
- ``debug`` - boolean (default True); if True, print the full
786
system command being executed.
787
788
EXAMPLES::
789
790
sage: hg_sage.rename('sage/misc/hg.py', 'sage/misc/hgnew.py', options='--dry-run')
791
Moving sage/misc/hg.py --> sage/misc/hgnew.py
792
cd ... && sage --hg mv --dry-run "sage/misc/hg.py" "sage/misc/hgnew.py"
793
"""
794
print "Moving %s --> %s"%(src,dest)
795
self('mv %s "%s" "%s"'%(options, src,dest), debug=debug)
796
797
move = rename
798
mv = rename
799
800
def log(self, branches=None, keyword=None, limit=None,
801
rev=None, merges=True, only_merges=False,
802
patch=None, template=False, include=None,
803
exclude=None, verbose=False, debug=True):
804
"""
805
Display the change log for this repository. This is a list of
806
changesets ordered by revision number.
807
808
By default this command outputs: changeset id and hash, tags,
809
non-trivial parents, user, date and time, and a summary for each
810
commit.
811
812
INPUT:
813
814
- ``branches`` - (string, default: None) show given
815
branches
816
817
- ``keyword`` - (string, default: None) search for a
818
keyword
819
820
- ``limit`` - (integer, default: None, or 20 in
821
notebook mdoe) limit number of changes displayed
822
823
- ``rev`` - (integer) show the specified revision
824
825
- ``merges`` - (bool, default: True) whether or not
826
to show merges
827
828
- ``only_merges`` - (bool, default: False) if true,
829
show only merges
830
831
- ``patch`` - (string, default: None) show given
832
patch
833
834
- ``template`` - (string, default: None) display with
835
template
836
837
- ``include`` - (string, default: None) include names
838
matching the given patterns
839
840
- ``exclude`` - (string, default: None) exclude names
841
matching the given patterns
842
843
- ``verbose`` - (bool, default: False) If true, the
844
list of changed files and full commit message is shown.
845
846
- ``debug`` - boolean (default True); if True, print the
847
full system command being executed.
848
849
EXAMPLES::
850
851
sage: hg_sage.log() # not tested
852
cd ... && sage --hg log --config pager.pager="LESS='R' less"
853
...
854
"""
855
if embedded() and limit is None:
856
limit = 20
857
options = ''
858
if branches:
859
options += '-b %s '%branches
860
if keyword:
861
options += '-k "%s" '%keyword
862
if limit:
863
options += '-l %s '%limit
864
if rev:
865
options += '-r %s '%rev
866
if not merges:
867
options += '--no-merges '
868
if only_merges:
869
options += '-m '
870
if patch:
871
options += '-p "%s"'%patch
872
if template:
873
options += '--template'
874
if include:
875
options += '-I "%s"'%include
876
if exclude:
877
options += '-X "%s"'%exclude
878
if verbose:
879
options = '-v ' + options
880
881
self('log %s %s %s'%(options, color(), pager()), debug=debug)
882
883
changes = log
884
history = log
885
886
def diff(self, files='', rev=None, options='', debug=True):
887
"""
888
Show differences between revisions for the specified files as a
889
unified diff.
890
891
By default this command tells you exactly what you have changed in
892
your working repository since you last committed changes.
893
894
INPUT:
895
896
- ``files`` - space separated list of files (relative
897
to self.dir())
898
899
- ``rev`` - None or a list of integers.
900
901
- ``options`` -- string (default ''). Some possibilities::
902
903
-a --text treat all files as text
904
-g --git use git extended diff format
905
-p --show-function show which function each change is in
906
-I --include PATTERN [+] include names matching the given patterns
907
-X --exclude PATTERN [+] exclude names matching the given patterns
908
909
- ``debug`` - boolean (default True); if True, print the
910
full system command being executed.
911
912
Differences between files are shown using the unified diff format.
913
914
When two revision arguments are given, then changes are shown
915
between those revisions. If only one revision is specified then
916
that revision is compared to the working directory, and, when no
917
revisions are specified, the working directory files are compared
918
to its parent.
919
920
EXAMPLES::
921
922
sage: hg_sage.diff() # not tested
923
cd ... && sage --hg diff --config pager.pager="LESS='R' less"
924
925
To see the changes in this file since revision 10000::
926
927
sage: hg_sage.diff('sage/misc/hg.py', rev=10000) # not tested
928
cd ... && sage --hg diff -r 10000 sage/misc/hg.py --config pager.pager="LESS='R' less"
929
...
930
"""
931
if not rev is None:
932
if not isinstance(rev, (list, tuple)):
933
rev = [rev]
934
extra_options = ' '.join(['-r %s'%r for r in rev]) + ' ' + files
935
else:
936
extra_options = files
937
self('diff %s %s %s %s'%(options, extra_options, color(), pager()),
938
debug=debug)
939
940
what = diff
941
942
def revert(self, files='', options='', rev=None, debug=True):
943
"""
944
Revert files or dirs to their states as of some revision.
945
946
.. note::
947
948
This command is most likely not what you are looking
949
for. ``revert`` will partially overwrite content in the
950
working directory without changing the working directory
951
parents. Use the method ``update(options='-r REV')`` to
952
check out earlier revisions, or ``update(options='--clean
953
.')`` to undo a merge which has added another parent.
954
955
With no revision specified, revert the named files or
956
directories to the contents they had in the parent of the
957
working directory. This restores the contents of the affected
958
files to an unmodified state and unschedules adds, removes,
959
copies, and renames. If the working directory has two parents,
960
you must explicitly specify a revision.
961
962
Using the ``rev`` argument, revert the given files or
963
directories to their contents as of a specific revision. This
964
can be helpful to "roll back" some or all of an earlier change.
965
Run ``hg_sage('help dates')`` for a list of formats valid for
966
the ``-d/--date`` option.
967
968
Revert modifies the working directory. It does not commit any
969
changes, or change the parent of the working directory. If you
970
revert to a revision other than the parent of the working
971
directory, the reverted files will thus appear modified
972
afterwards.
973
974
If a file has been deleted, it is restored. If the executable
975
mode of a file was changed, it is reset.
976
977
If names are given, all files matching the names are
978
reverted. If no arguments are given, no files are reverted.
979
To revert all files in the repository, pass the argument
980
``options='--all'``.
981
982
Modified files are saved with a .orig suffix before
983
reverting. To disable these backups, use
984
``options='--no-backup'``.
985
986
If ``debug`` is True, also print the full system command being
987
executed.
988
989
OPTIONS::
990
991
-a --all revert all changes when no arguments given
992
-d --date DATE tipmost revision matching date
993
--no-backup do not save backup copies of files
994
-I --include PATTERN [+] include names matching the given patterns
995
-X --exclude PATTERN [+] exclude names matching the given patterns
996
-n --dry-run do not perform actions, just print output
997
--mq operate on patch repository
998
999
EXAMPLES::
1000
1001
sage: hg_sage.revert('sage/misc/hg.py', rev=12000, options='--dry-run')
1002
cd ... && sage --hg revert --dry-run -r 12000 sage/misc/hg.py
1003
"""
1004
if not rev is None:
1005
options = options +' -r %s %s'%(rev, files)
1006
else:
1007
options = options + files
1008
self('revert %s'%options, debug=debug)
1009
1010
def dir(self):
1011
"""
1012
Return the directory where this repository is located.
1013
1014
EXAMPLES::
1015
1016
sage: os.path.realpath(hg_sage.dir()).startswith(os.path.realpath(os.environ['SAGE_ROOT']))
1017
True
1018
"""
1019
return self.__dir
1020
1021
def pull_url(self):
1022
"""
1023
Return the default 'master url' for this repository.
1024
1025
EXAMPLES::
1026
1027
sage: hg_sage.pull_url()
1028
'http://hg.sagemath.org/sage-main/'
1029
"""
1030
return self.__pull_url
1031
1032
def push_url(self):
1033
"""
1034
Return the default url for uploading this repository.
1035
1036
EXAMPLES::
1037
1038
sage: hg_sage.push_url()
1039
'http://hg.sagemath.org/sage-main/'
1040
"""
1041
return self.__push_url
1042
1043
1044
def help(self, cmd='', debug=True):
1045
r"""
1046
Print a help message about ``cmd``, or if ``cmd`` is omitted,
1047
print a general Mercurial help message.
1048
1049
If ``debug`` is True, also print the full system command being
1050
executed.
1051
1052
If this hg object is called hg_sage, then you call a command using
1053
``hg_sage('usual hg command line notation')``. Type "hg_sage?" for
1054
more information.
1055
1056
EXAMPLES::
1057
1058
sage: hg_sage.help() # not tested
1059
Mercurial Distributed SCM
1060
1061
list of commands:
1062
...
1063
sage: hg_sage.help('status') # not tested
1064
hg status [OPTION]... [FILE]...
1065
1066
aliases: st
1067
1068
show changed files in the working directory
1069
...
1070
"""
1071
self('%s --help %s'%(cmd, pager()), debug=debug)
1072
1073
def outgoing(self, url=None, opts='', debug=True):
1074
"""
1075
Use this to find changsets that are in your branch, but not in the
1076
specified destination repository. If no destination is specified,
1077
the official repository is used. By default, :meth:`push_url` is used.
1078
1079
From the Mercurial documentation:
1080
1081
Show changesets not found in the specified destination
1082
repository or the default push location. These are the
1083
changesets that would be pushed if a push was requested.
1084
1085
See :meth:`push` for valid destination format details.
1086
1087
INPUT:
1088
1089
1090
- ``url`` - (Default: :meth:`push_url`) the official
1091
repository
1092
1093
- ``http://[user@]host[:port]/[path]``
1094
1095
- ``https://[user@]host[:port]/[path]``
1096
1097
- ``ssh://[user@]host[:port]/[path]``
1098
1099
- local directory (starting with a /)
1100
1101
- name of a branch (for hg_sage); no /'s
1102
1103
- ``options`` - (Default: None)::
1104
1105
-M --no-merges do not show merges
1106
-f --force run even when remote repository is unrelated
1107
-p --patch show patch
1108
--style display using template map file
1109
-r --rev a specific revision you would like to push
1110
-n --newest-first show newest record first
1111
--template display with template
1112
-e --ssh specify ssh command to use
1113
--remotecmd specify hg command to run on the remote side
1114
1115
- ``debug`` - if True, print the full system command being
1116
executed.
1117
1118
EXAMPLES::
1119
1120
sage: hg_sage.outgoing() # not tested
1121
cd ... && sage --hg outgoing http://hg.sagemath.org/sage-main/ --config pager.pager="LESS='R' less"
1122
comparing with http://hg.sagemath.org/sage-main/
1123
searching for changes
1124
...
1125
"""
1126
if url is None:
1127
url = self.__push_url
1128
1129
if not '/' in url:
1130
url = '%s/devel/sage-%s'%(SAGE_ROOT, url)
1131
1132
self('outgoing %s %s %s' % (opts, url, pager()), debug=debug)
1133
1134
def pull(self, url=None, options='-u', debug=True):
1135
"""
1136
Pull all new patches from the repository at the given url, or use
1137
the default 'official' repository if no url is specified.
1138
1139
INPUT:
1140
1141
- ``url`` - (Default: :meth:`pull_url`) the official
1142
repository
1143
1144
- ``http://[user@]host[:port]/[path]``
1145
1146
- ``https://[user@]host[:port]/[path]``
1147
1148
- ``ssh://[user@]host[:port]/[path]``
1149
1150
- local directory (starting with a /)
1151
1152
- name of a branch (for hg_sage); no /'s
1153
1154
- ``options`` - (Default: '-u')::
1155
1156
-u --update update the working directory to tip after pull
1157
-e --ssh specify ssh command to use
1158
-f --force run even when remote repository is unrelated
1159
-r --rev a specific revision you would like to pull
1160
--remotecmd specify hg command to run on the remote side
1161
1162
- ``debug`` - if True, print the full system command being
1163
executed.
1164
1165
Some notes about using SSH with Mercurial:
1166
1167
- SSH requires an accessible shell account on the destination
1168
machine and a copy of hg in the remote path or specified
1169
with as remotecmd.
1170
1171
- path is relative to the remote user's home directory by
1172
default. Use an extra slash at the start of a path to
1173
specify an absolute path: ``ssh://example.com//tmp/repository``
1174
1175
- Mercurial doesn't use its own compression via SSH; the right
1176
thing to do is to configure it in your /.ssh/ssh_config,
1177
e.g.::
1178
1179
Host *.mylocalnetwork.example.com
1180
Compression off
1181
Host *
1182
Compression on
1183
1184
Alternatively specify 'ssh -C' as your ssh command in your
1185
hgrc or with the -ssh command line option.
1186
1187
EXAMPLES::
1188
1189
sage: hg_sage.pull() # not tested
1190
cd ... && sage --hg pull http://hg.sagemath.org/sage-main/
1191
...
1192
"""
1193
self._ensure_safe()
1194
1195
if url is None:
1196
url = self.__pull_url
1197
if not '/' in url:
1198
url = '%s/devel/sage-%s'%(SAGE_ROOT, url)
1199
1200
self('pull %s %s'%(options, url), debug=debug)
1201
if self.__target == 'sage':
1202
print ""
1203
print "Now building the new Sage libraries"
1204
os.system('sage -b')
1205
print "You *MUST* restart Sage in order for the changes to take effect!"
1206
1207
print "If it says use 'hg merge' above, then you should"
1208
print "type hg_%s.merge()."%self.__obj_name
1209
1210
def push(self, url=None, options='', debug=True):
1211
"""
1212
Push all new patches from the repository to the given destination.
1213
1214
INPUT:
1215
1216
- ``url`` - (Default: :meth:`push_url`) the official
1217
repository
1218
1219
- ``http://[user@]host[:port]/[path]``
1220
1221
- ``https://[user@]host[:port]/[path]``
1222
1223
- ``ssh://[user@]host[:port]/[path]``
1224
1225
- local directory (starting with a /)
1226
1227
- name of a branch (for hg_sage); no /'s
1228
1229
- ``options`` - (Default: '')::
1230
1231
-e --ssh specify ssh command to use
1232
-f --force run even when remote repository is unrelated
1233
-r --rev a specific revision you would like to pull
1234
--remotecmd specify hg command to run on the remote side
1235
1236
- ``debug`` - if True, print the full system command being
1237
executed.
1238
1239
Some notes about using SSH with Mercurial:
1240
1241
- SSH requires an accessible shell account on the destination
1242
machine and a copy of hg in the remote path or specified
1243
with as remotecmd.
1244
1245
- path is relative to the remote user's home directory by
1246
default. Use an extra slash at the start of a path to
1247
specify an absolute path: ``ssh://example.com//tmp/repository``
1248
1249
- Mercurial doesn't use its own compression via SSH; the right
1250
thing to do is to configure it in your /.ssh/ssh_config,
1251
e.g.::
1252
1253
Host *.mylocalnetwork.example.com
1254
Compression off
1255
Host *
1256
Compression on
1257
1258
Alternatively specify 'ssh -C' as your ssh command in your
1259
hgrc or with the -ssh command line option.
1260
1261
EXAMPLES::
1262
1263
sage: hg_sage.push() # not tested
1264
cd ... && sage --hg push http://hg.sagemath.org/sage-main/
1265
...
1266
"""
1267
self._ensure_safe()
1268
1269
if url is None:
1270
url = self.__push_url
1271
if not '/' in url:
1272
url = '%s/devel/sage-%s'%(SAGE_ROOT, url)
1273
1274
self('push %s %s'%(options, url), debug=debug)
1275
1276
1277
def merge(self, options='', debug=True):
1278
"""
1279
Merge working directory with another revision
1280
1281
Merge the contents of the current working directory and the
1282
requested revision. Files that changed between either parent are
1283
marked as changed for the next commit and a commit must be
1284
performed before any further updates are allowed.
1285
1286
INPUT:
1287
1288
- ``options`` - default: ''::
1289
1290
-f --force force a merge with outstanding changes
1291
-r --rev revision to merge
1292
1293
- ``debug`` - if True, print the full system command being
1294
executed.
1295
1296
EXAMPLES::
1297
1298
sage: hg_sage.merge() # not tested
1299
cd ... && sage --hg merge
1300
"""
1301
self('merge %s'%options, debug=debug)
1302
1303
def update(self, options='', debug=True):
1304
"""
1305
update or merge working directory
1306
1307
Update the working directory to the specified revision.
1308
1309
If there are no outstanding changes in the working directory and
1310
there is a linear relationship between the current version and the
1311
requested version, the result is the requested version.
1312
1313
To merge the working directory with another revision, use the merge
1314
command.
1315
1316
By default, update will refuse to run if doing so would require
1317
merging or discarding local changes.
1318
1319
aliases: up, checkout, co
1320
1321
INPUT:
1322
1323
- ``options`` - string (default: '')::
1324
1325
-C --clean overwrite locally modified files
1326
-d --date tipmost revision matching date
1327
-r --rev revision
1328
1329
- ``debug`` - if True, print the full system command being
1330
executed.
1331
1332
EXAMPLES::
1333
1334
sage: hg_sage.update() # not tested
1335
cd ... && sage --hg update
1336
"""
1337
self('update %s'%options, debug=debug)
1338
1339
up = update
1340
checkout = update
1341
co = update
1342
1343
def head(self, options='', debug=True):
1344
"""
1345
Show all repository head changesets.
1346
1347
Repository "heads" are changesets that don't have children
1348
changesets. They are where development generally takes place and
1349
are the usual targets for update and merge operations.
1350
1351
INPUT:
1352
1353
- ``options`` - string (default: '')::
1354
1355
-r --rev show only heads which are descendants of rev
1356
--style display using template map file
1357
--template display with template
1358
1359
- ``debug`` - if True, print the full system command being
1360
executed.
1361
1362
EXAMPLES::
1363
1364
sage: hg_sage.head() # random
1365
cd ... && sage --hg head
1366
changeset: 15825:6ca08864b80c
1367
tag: tip
1368
user: Jeroen Demeyer <[email protected]>
1369
date: Tue Jun 07 12:31:57 2011 +0000
1370
summary: 4.7.1.alpha2
1371
"""
1372
self('head %s'%options, debug=debug)
1373
1374
heads = head
1375
1376
def switch(self, name=None):
1377
r"""
1378
Switch to a different branch. You must restart Sage after
1379
switching.
1380
1381
Only available for ``hg_sage.``
1382
1383
INPUT:
1384
1385
- ``name`` - name of a Sage branch (default: None)
1386
1387
If the name is not given, this function returns a list of all
1388
branches.
1389
1390
EXAMPLES::
1391
1392
sage: hg_sage.switch() # random
1393
['main']
1394
sage: hg_sage.switch('new') # not tested
1395
<BLANKLINE>
1396
----------------------------------------------------------
1397
Building and installing modified Sage library files.
1398
<BLANKLINE>
1399
...
1400
"""
1401
if name is None:
1402
s = os.popen('ls -l %s/devel/ |grep sage-'%os.environ['SAGE_ROOT']).read()
1403
t = s.split('\n')
1404
v = []
1405
for X in t:
1406
i = X.rfind('sage-')
1407
n = X[i+5:]
1408
if n != '':
1409
v.append(n)
1410
v = list(set(v))
1411
v.sort()
1412
return v
1413
os.system('sage -b "%s"'%name)
1414
1415
def clone(self, name, rev=None):
1416
r"""
1417
Clone the current branch of the Sage library, and make it active.
1418
1419
Only available for the ``hg_sage`` repository.
1420
1421
Use ``hg_sage.switch('branch_name')`` to switch to a
1422
different branch. You must restart Sage after switching.
1423
1424
INPUT:
1425
1426
- ``name`` - string
1427
1428
- ``rev`` - integer or None (default)
1429
1430
1431
If rev is None, clones the latest recorded version of the
1432
repository. This is very fast, e.g., about 30-60 seconds (including
1433
any build). If a specific revision is specified, cloning may take
1434
much longer (e.g., 5 minutes), since all Pyrex code has to be
1435
regenerated and compiled.
1436
1437
EXAMPLES:
1438
1439
Make a clone of the repository called testing. A copy of the
1440
current repository will be created in a directory sage-testing,
1441
then SAGE_ROOT/devel/sage will point to sage-testing, and when you
1442
next restart Sage that's the version you'll be using.
1443
1444
::
1445
1446
sage: hg_sage.clone('testing') # not tested
1447
...
1448
1449
Make a clone of the repository as it was at revision 1328.
1450
1451
::
1452
1453
sage: hg_sage.clone('testing', 1328) # not tested
1454
...
1455
"""
1456
if not self.__cloneable:
1457
raise RuntimeError, "only available for hg_sage"
1458
name = '_'.join(str(name).split())
1459
if rev is None:
1460
os.system('sage -clone %s'%name)
1461
else:
1462
os.system('sage -clone %s -r %s'%(name, int(rev)))
1463
1464
def commit(self, files='', comment=None, options='', diff=True,
1465
debug=True):
1466
r"""
1467
Commit your changes to the repository.
1468
1469
Quit out of the editor without saving to not record your changes.
1470
1471
INPUT:
1472
1473
- ``files`` - space separated string of file names (optional)
1474
If specified only those files are committed. The path must be
1475
absolute or relative to self.dir().
1476
1477
- ``comment`` - optional changeset comment. If you don't give
1478
it you will be dumped into an editor. If you're using the
1479
Sage notebook, you *must* specify a comment.
1480
1481
- ``options`` - string::
1482
1483
-A --addremove mark new/missing files as added/removed before committing
1484
-m --message use <text> as commit message
1485
-l --logfile read the commit message from <file>
1486
-d --date record datecode as commit date
1487
-u --user record user as committer
1488
-I --include include names matching the given patterns
1489
-X --exclude exclude names matching the given patterns
1490
1491
- ``diff`` - (default: True) if True show diffs between your repository
1492
and your working repository before recording changes.
1493
1494
- ``debug`` - if True, print the full system command being
1495
executed.
1496
1497
.. note::
1498
1499
If you create new files you should first add them with the
1500
add method.
1501
1502
EXAMPLES::
1503
1504
sage: hg_sage.commit('hg.py', comment='miscellaneous fixes') # not tested
1505
cd ... && sage --hg commit -m "miscellaneous fixes" hg.py
1506
"""
1507
if embedded() and comment is None:
1508
raise RuntimeError, "You're using the Sage notebook, so you *must* explicitly specify the comment in the commit command."
1509
if diff:
1510
self.diff(files)
1511
1512
if isinstance(files, (list, tuple)):
1513
files = ' '.join([str(x) for x in files])
1514
1515
if comment:
1516
self('commit %s -m "%s" %s '%(options, comment, files), debug=debug)
1517
else:
1518
self('commit %s %s'%(options, files), debug=debug)
1519
1520
record = commit
1521
ci = commit
1522
1523
def rollback(self, debug=True):
1524
"""
1525
Remove recorded patches without changing the working copy.
1526
1527
If ``debug`` is True, also print the full system command being
1528
executed.
1529
1530
EXAMPLES::
1531
1532
sage: hg_sage.rollback() # not tested
1533
cd ... && sage --hg rollback
1534
"""
1535
self('rollback', debug=debug)
1536
1537
def bundle(self, filename, options='', url=None, base=None, to=None,
1538
debug=True):
1539
r"""
1540
Create an hg changeset bundle with the given filename against the
1541
repository at the given url (which is by default the 'official'
1542
Sage repository, unless :meth:`push_url` is changed in a setup file).
1543
1544
If you have internet access, it's best to just do
1545
``hg_sage.bundle(filename)``. If you don't find a
1546
revision r that you and the person unbundling both have (by looking
1547
at ``hg_sage.log()``), then do
1548
``hg_sage.bundle(filename, base=r)``.
1549
1550
Use ``hg_sage.inspect('file.bundle')`` to inspect the resulting bundle.
1551
1552
This is a file that you could post to a web page. However,
1553
Sage now typically accepts only patch files at its Trac
1554
server. The file will be written to the current directory.
1555
1556
INPUT:
1557
1558
- ``filename`` - output file in which to put bundle
1559
1560
- ``options`` - pass to hg
1561
1562
- ``url`` - url to bundle against (default:
1563
``SAGE_SERVER``, or :meth:`push_url`)
1564
1565
- ``base`` - a base changeset revision number to
1566
bundle against (doesn't require internet access)
1567
1568
- ``debug`` - if True, print the full system command being
1569
executed.
1570
1571
EXAMPLES::
1572
1573
sage: hg_sage.bundle('new-bundle') # not tested
1574
Writing to /.../new-bundle.hg
1575
cd ... && sage --hg bundle tmphg http://hg.sagemath.org/sage-main/
1576
searching for changes
1577
133 changesets found
1578
Successfully created hg patch bundle /.../new-bundle.hg
1579
"""
1580
if not base is None:
1581
url = ''
1582
options = '--base=%s %s'%(int(base), options)
1583
1584
if url is None:
1585
url = self.__push_url
1586
1587
# make sure that we don't accidentally create a file ending in '.hg.hg'
1588
if filename[-3:] == '.hg':
1589
filename = filename[:-3]
1590
# We write to a local tmp file, then move, since under
1591
# windows hg has a bug that makes it fail to write
1592
# to any filename that is at all complicated!
1593
filename = os.path.abspath(filename)
1594
if filename[-3:] != '.hg':
1595
filename += '.hg'
1596
print 'Writing to %s'%filename
1597
tmpfile = '%s/tmphg'%self.__dir
1598
if os.path.exists(tmpfile):
1599
os.unlink(tmpfile)
1600
self('bundle %s tmphg %s'%(options, url), debug=debug)
1601
if os.path.exists(tmpfile):
1602
shutil.move(tmpfile, filename)
1603
print 'Successfully created hg patch bundle %s'%filename
1604
if not to is None:
1605
os.system('scp "%s" %s'%(filename, to))
1606
else:
1607
print 'Problem creating hg patch bundle %s'%filename
1608
1609
send = bundle
1610
save = send
1611
1612
# Mercurial queues
1613
1614
def qseries(self, verbose=False, debug=True):
1615
"""
1616
Mercurial queues: print the series file.
1617
1618
If optional argument ``verbose`` is True, then also print the
1619
first line of each patch's header.
1620
1621
If ``debug`` is True, also print the full system command being
1622
executed.
1623
1624
EXAMPLES::
1625
1626
sage: hg_sage.qseries()
1627
cd ... && sage --hg qseries
1628
"""
1629
options = "--summary" if verbose else ""
1630
self('qseries %s %s' % (options, color(),), debug=debug)
1631
1632
def qapplied(self, verbose=False, debug=True):
1633
"""
1634
Mercurial queues: print the patches in the queue which have
1635
been applied.
1636
1637
If optional argument ``verbose`` is True, then also print the
1638
first line of each patch's header.
1639
1640
If ``debug`` is True, also print the full system command being
1641
executed.
1642
1643
EXAMPLES::
1644
1645
sage: hg_sage.qapplied()
1646
cd ... && sage --hg qapplied
1647
"""
1648
options = "--summary" if verbose else ""
1649
self('qapplied %s %s' % (options, color(),), debug=debug)
1650
1651
def qunapplied(self, verbose=False, debug=True):
1652
"""
1653
Mercurial queues: print the patches in the queue which have
1654
not yet been applied.
1655
1656
If optional argument ``verbose`` is True, then also print the
1657
first line of each patch's header.
1658
1659
If ``debug`` is True, also print the full system command being
1660
executed.
1661
1662
EXAMPLES::
1663
1664
sage: hg_sage.qunapplied()
1665
cd ... && sage --hg qunapplied
1666
"""
1667
options = "--summary" if verbose else ""
1668
self('qunapplied %s %s' % (options, color(),), debug=debug)
1669
1670
def qimport(self, filename, options='', debug=True):
1671
"""
1672
Mercurial queues: insert the patch from ``filename`` in the queue.
1673
1674
INPUT:
1675
1676
- ``filename`` -- string
1677
- ``options`` -- string (default '')::
1678
1679
-e --existing import file in patch directory
1680
-n --name NAME name of patch file
1681
-f --force overwrite existing files
1682
-r --rev REV [+] place existing revisions under mq control
1683
-g --git use git extended diff format
1684
-P --push qpush after importing
1685
1686
- ``debug`` -- (default True): if True, print the full system
1687
command being executed.
1688
1689
EXAMPLES::
1690
1691
sage: hg_sage.qimport('old.patch') # not tested
1692
cd ... && sage --hg qimport old.patch ...
1693
"""
1694
if filename.startswith("http://") or filename.startswith("https://"):
1695
filename = get_remote_file(filename, verbose=True)
1696
self._ensure_safe()
1697
self('qimport %s %s' % (options, os.path.abspath(filename)),
1698
debug=debug)
1699
1700
def qdelete(self, patches, keep_patch=False, debug=True):
1701
"""
1702
Mercurial queues: delete the named patch from the queue.
1703
1704
INPUT:
1705
1706
- ``patches`` -- string, a patch or list of patches separated by
1707
white space
1708
1709
- ``keep_patch`` -- (default False): if True, keep the patch
1710
files in the patch directory.
1711
1712
- ``debug`` -- (default True): if True, print the full system
1713
command being executed.
1714
1715
EXAMPLES::
1716
1717
sage: hg_sage.qdelete('old.patch new.patch') # not tested
1718
cd ... && sage --hg qdelete old.patch new.patch ...
1719
"""
1720
options = "--keep" if keep_patch else ""
1721
self('qdelete %s %s' % (options, patches),
1722
debug=debug)
1723
1724
qremove = qdelete
1725
1726
def qpush(self, force=False, all=False, options='', debug=True):
1727
"""
1728
Mercurial queues: push the next patch onto the stack.
1729
1730
INPUT:
1731
1732
- ``force`` -- boolean (default False): if True, apply even if the
1733
patch has rejects.
1734
1735
- ``all`` -- boolean (default False): if True, apply all unapplied
1736
patches.
1737
1738
- ``options`` -- string (default ''): extra options to pass to the command.
1739
1740
- ``debug`` -- (default True): if True, print the full system
1741
command being executed.
1742
1743
EXAMPLES::
1744
1745
sage: hg_sage.qpush() # not tested
1746
cd ... && sage --hg qpush
1747
"""
1748
extra_options = ''
1749
if force:
1750
extra_options += ' --force'
1751
if all:
1752
extra_options += ' --all'
1753
self('qpush %s %s' % (extra_options, options),
1754
debug=debug)
1755
1756
def qpop(self, patch='', force=False, all=False, debug=True):
1757
"""
1758
Mercurial queues: pop the top of the patch stack, or if given
1759
a patch, pop patches off of the stack until it is at the top.
1760
1761
INPUT:
1762
1763
- ``patch`` -- string (default ''): if nonempty, this should
1764
name an applied patch, and then the command will pop patches
1765
off the stack until ``patch`` is at the top.
1766
1767
- ``force`` -- boolean (default False): if True, forget any
1768
changes to patched files.
1769
1770
- ``all`` -- boolean (default False): if True, pop all
1771
patches.
1772
1773
- ``debug`` -- (default True): if True, print the full system
1774
command being executed.
1775
1776
EXAMPLES::
1777
1778
sage: hg_sage.qpop() # not tested
1779
cd ... && sage --hg qpop
1780
"""
1781
extra_options = ''
1782
if force:
1783
extra_options += ' --force'
1784
if all:
1785
extra_options += ' --all'
1786
if patch:
1787
extra_options += ' %s' % patch
1788
self('qpop %s' % extra_options, debug=debug)
1789
1790
def qrefresh(self, options='', debug=True):
1791
"""
1792
Mercurial queues: update the current patch.
1793
1794
INPUT:
1795
1796
- ``options`` -- string (default ''). Some possibilities::
1797
1798
-e --edit edit commit message
1799
-g --git use git extended diff format
1800
-I --include PATTERN [+] include names matching the given patterns
1801
-X --exclude PATTERN [+] exclude names matching the given patterns
1802
-m --message TEXT use text as commit message
1803
1804
- ``debug`` -- (default True): if True, print the full system
1805
command being executed.
1806
1807
EXAMPLES::
1808
1809
sage: hg_sage.qrefresh() # not tested
1810
cd ... && sage --hg qrefresh
1811
"""
1812
self('qrefresh %s' % options, debug=debug)
1813
1814
def qdiff(self, options='', debug=True):
1815
"""
1816
Mercurial queues: show a diff including the current patch and
1817
any more recent changes, thus showing what the current patch
1818
would become after :meth:`qrefresh`.
1819
1820
Use :meth:`diff` if you only want to see the changes made
1821
since the last :meth:`qrefresh`.
1822
1823
INPUT:
1824
1825
- ``options`` -- string (default ''). Some possibilities::
1826
1827
-a --text treat all files as text
1828
-g --git use git extended diff format
1829
-p --show-function show which function each change is in
1830
-I --include PATTERN [+] include names matching the given patterns
1831
-X --exclude PATTERN [+] exclude names matching the given patterns
1832
1833
- ``debug`` -- (default True): if True, print the full system
1834
command being executed.
1835
1836
EXAMPLES::
1837
1838
sage: hg_sage.qdiff() # not tested
1839
cd ... && sage --hg qdiff ...
1840
"""
1841
self('qdiff %s %s %s' % (options, color(), pager()), debug=debug)
1842
1843
def qnew(self, patch, options='', debug=True):
1844
"""
1845
Mercurial queues: create a new patch.
1846
1847
INPUT:
1848
1849
- ``patch`` -- string, the name of the patch.
1850
1851
- ``options`` -- string (default ''). Some possibilities::
1852
1853
-e --edit edit commit message
1854
-g --git use git extended diff format
1855
-I --include PATTERN [+] include names matching the given patterns
1856
-X --exclude PATTERN [+] exclude names matching the given patterns
1857
-m --message TEXT use text as commit message
1858
1859
- ``debug`` -- (default True): if True, print the full system
1860
command being executed.
1861
1862
EXAMPLES::
1863
1864
sage: hg_sage.qnew('my_new.patch') # not tested
1865
cd ... && sage --hg qnew my_new.patch
1866
"""
1867
self('qnew %s %s' % (patch, options), debug=debug)
1868
1869
1870
##############################################################################
1871
# Initialize the actual repositories.
1872
##############################################################################
1873
1874
import misc
1875
1876
SAGE_ROOT = misc.SAGE_ROOT
1877
DEFAULT_SERVER = "http://hg.sagemath.org"
1878
1879
SAGE_INCOMING_SERVER = os.getenv("SAGE_INCOMING_SERVER")
1880
if SAGE_INCOMING_SERVER is None:
1881
try:
1882
SAGE_INCOMING_SERVER = os.environ['SAGE_HG_SERVER'].strip('/')
1883
except KeyError:
1884
#print "Falling back to a hard coded sage server in misc/hg.py"
1885
SAGE_INCOMING_SERVER = DEFAULT_SERVER
1886
1887
SAGE_OUTGOING_SERVER = os.getenv("SAGE_OUTGOING_SERVER")
1888
if SAGE_OUTGOING_SERVER is None:
1889
SAGE_OUTGOING_SERVER = SAGE_INCOMING_SERVER
1890
1891
if (SAGE_INCOMING_SERVER == DEFAULT_SERVER): ## Always uses the "main" branch on the default server.
1892
temp_in_branch_name = "main"
1893
else:
1894
temp_in_branch_name = branch_current_hg()
1895
1896
if (SAGE_OUTGOING_SERVER == DEFAULT_SERVER): ## Always uses the "main" branch on the default server.
1897
temp_out_branch_name = "main"
1898
else:
1899
temp_out_branch_name = branch_current_hg()
1900
1901
1902
if (SAGE_INCOMING_SERVER != DEFAULT_SERVER) or (SAGE_OUTGOING_SERVER != DEFAULT_SERVER):
1903
print "Non-default server settings detected:"
1904
print " Incoming Server = " + SAGE_INCOMING_SERVER + ''.join([" (default)" \
1905
for i in range(1) if (SAGE_INCOMING_SERVER == DEFAULT_SERVER)])
1906
print " Outgoing Server = " + SAGE_OUTGOING_SERVER + ''.join([" (default)" \
1907
for i in range(1) if (SAGE_OUTGOING_SERVER == DEFAULT_SERVER)])
1908
print
1909
1910
1911
hg_sage = HG('%s/devel/sage'%SAGE_ROOT,
1912
'Sage Library Source Code',
1913
pull_url='%s/sage-%s/'%(SAGE_INCOMING_SERVER, temp_in_branch_name),
1914
push_url='%s/sage-%s/'%(SAGE_OUTGOING_SERVER, temp_out_branch_name),
1915
cloneable=True,
1916
obj_name='sage')
1917
1918
hg_scripts = HG('%s/local/bin/'%SAGE_ROOT,
1919
'Sage Scripts',
1920
pull_url='%s/scripts-main/'%SAGE_INCOMING_SERVER,
1921
push_url='%s/scripts-main/'%SAGE_OUTGOING_SERVER,
1922
obj_name='scripts')
1923
1924
hg_extcode = HG('%s/data/extcode'%SAGE_ROOT,
1925
'Sage External System Code (e.g., PARI, MAGMA, etc.)',
1926
pull_url='%s/extcode-main/'%SAGE_INCOMING_SERVER,
1927
push_url='%s/extcode-main/'%SAGE_OUTGOING_SERVER,
1928
obj_name='extcode')
1929
1930
1931
hg_root = HG(SAGE_ROOT,
1932
'Sage Root',
1933
pull_url=SAGE_INCOMING_SERVER,
1934
push_url=SAGE_OUTGOING_SERVER,
1935
obj_name='root')
1936
1937
hg_sagenb = HG('%s/devel/sagenb' % SAGE_ROOT,
1938
'SageNB Source Code',
1939
pull_url='http://boxen.math.washington.edu:8123',
1940
push_url='http://boxen.math.washington.edu:8123',
1941
obj_name='sagenb')
1942
1943