The manual says that -f means
Force the creation of extra revisions in order to explicitly record that files have been copied. Deleted source files are copied if they
do not exist in the target, and files that are already identical are
copied if they are not connected by existing integration records.
Honestly, I don't quite understand when p4 copy -f can be very useful.
Could someone please show me some simple examples of the use cases of p4 copy -f?
Thank you.
If you’ve never encountered a situation where p4 copy -f seems like it might be useful, count yourself lucky and forget about it; there are a number of options in Perforce that are only ever useful if you’ve already dug yourself a hole and are determined to keep digging, and this is one of them.
That said, the classic case is:
Add foo in A.
Branch A to B.
Delete foo in B.
Branch B to C.
Merge C to A.
If foo never existed in C, it will not be included in a merge from C, so the change from step 3 is “lost” during the merge in step 5. Using p4 copy -f in step 4 prevents this by creating a dummy file in C that can propagate the delete to A.
Note that reparenting branches like this (going from A to B to C to A, rather than going from A to B to A) is not typically recommended as a best practice because it makes merging much more complicated in general.
Related
In VS2015 there is a useful tool for finding what is holding on to a reference to an object. However, in the spaghetti-like code that I am working in expanding this tree out has many leaves that end with [cycle detected] (e.g. A has a reference to B and B has a reference to A). For example:
Is there a way to filter out the branches that contain just leaves with cycles? Or a way to export the data here?
I was searching the web on tutorials / examples on how to use the Undo Monad Transformer but haven't found any.
Could someone please give a minimalistic example that shows how to use it?
Or pointing out a book where it is explained would be helpful too.
I would like to use it to implement undo/redo operations in a simple editor.
I can't find any tutorials either, but I think I understand this well enough to explain.
We first need to cobble together a type to represent our editors current state, for now will just do
type EditorState = Int
Then we can give this to our Undo monad
type Editor = Undo EditorState
Now we can do something like
fakeUser = do
put 1 -- Current state is 1
put 2 -- Current state is 2, 1 is saved in undo buffer
put 3 -- Current state is 3, 1 and 2 are saved
undo -- Move 3 to redo buffer, pop 2 off of undo buffer, current state is 2
redo -- reverse of the above, current state is 3
So you can think of this as a cursor in a list*, and we can move back and forth in this list where going left means we "undo" things and going right means we "redo" things. Using put sticks an element into the list at the current point and moves the old element to the undo buffer.
I would recommend not relying on the MonadState instance to do insertions because it hints a bit too much at the internals of Undo and it complicates things if we wanted to track other state through our editor.
However, this is a pretty simple piece of code that you could update to not use MonadState, get rid of the datatype contexts, remove the dependency on -f-glasgow-extensions which is frowned upon and then upload to hackage as a simple library if you have a bit of time.
*The name of such a structure is a "zipper"
I have only been programming in Natural for a couple of weeks over the course of a couple of years. I only do enough of it to get myself by.
Question: What is the difference between the MOVE a TO b and the a = b?
Code:
MOVE A TO B
MOVE D TO Y
Or
A = B
C = D
If you are using a Licensed product, you should have access to documentation at your site.
Software AG are the vendor. I found this with a simple internet search: http://documentation.softwareag.com/natural/nat638vms/general/print.htm
That is a manual for Natural on OpenVMS. It makes references to the Mainframe version, and looks good enough to answer your question.
This seems to be, at the simplest level, they are the same. However, if you want to do a calculation, you need the COMPUTE =, that can't be done with MOVE. There are various formats of the MOVE statement.
I have never used Natural, and can't test it. You have access to the product, that along with documentation will allow you to provide a full answer for yourself.
I think from what I can remember of Natural that basically they are they same. But I also remember that there are some difference.
For the most part I used = just because if you are using C++ that is a more common way of looking at it.
MOVE Your-Value TO Another-Value
is for the most part equal to
Another-Value = Your-Value
But I think where it is different slightly is as to what computations that you can and cannot perform with the = rather than the MOVE. You can MOVE to multiple values like below but the = can only move to a single variable.
MOVE A TO C D BaseBallScore
This is very useful if you have to move a lot of values at one time to several different counters but you could move one at a time. Like below
MOVE A TO C
MOVE A TO D
MOVE A TO BaseBallScore
There are also some functions that you can use with the MOVE that make it a nice option. Such as rounding a number
MOVE ROUNDED Value To NewValue <-- ROUNDED can take different parameters
Here is another function SUBSTRING that will let you move a part of a string to another part of the string. Normally I use the = just because that is how the boss does it but the MOVE statement gives a programmer a bit more flexibility.
MOVE SUBSTRING(#A,5,8) TO #B
An online reference for the move is located here:
http://documentation.softwareag.com/natural/nat638vms/print/sm.pdf
Problem specification:
I am currently searching for a elegant and/but efficient solution to a problem that i guess is quite common. Consider the following situation:
I defined a fileformat based on a BTree that is defined (in a simplified way) like this:
data FileTree = FileNode [Key] [FileOffset]
| FileLeaf [Key] [Data]
Reading and writing this from a file to a lazy data structure is implemented and works just fine. This will result in a instance of:
data MemTree = MemNode [Key] [MemTree]
| MemLeaf [Key] [Data]
Now my goal is to have a generic function updateFile :: FilePath -> (MemTree -> MemTree) -> IO () that will read in the FileTree and convert it into a MemTree, apply the MemTree -> MemTree function and write back the changes to the tree structure. The problem is that the FileOffsets have to be conserved somehow.
I have two approaches to this problem. Both of them lack in elegance and/or efficiency:
Approach 1: Extend MemTree to contain the offsets
This approach extends the MemTree to contain the offsets:
data MemTree = MemNode [Key] [(MemTree, Maybe FileOffset)]
| MemNode [Key] [Data]
The read function would then read in the FileTree and stores the FileOffset alongside the MemTree reference. Writing will checks if a reference already has an associated offset and if it does it just uses it.
Pros: easy to implement, no overhead to find the offset
Cons: exposes internal to the user who is responsible to set the offset to Nothing
Approach 2: Store offsets in a secondary structure
Another way to attack this problem is to read in the FileTree and create a StableName.Map that holds onto the FileOffsets. That way (and if i understand the semantics of StableName correctly) it should be possible to take the final MemTree and lookup the StableName of each node in the the StableName.Map. If there is an entry the node is clean and doesn't have to be written again.
Pros: doesn't expose the internals to the user
Cons: involves overhead for lookups in the map
Conclusion
These are the two approaches i can think of. The first one should be more efficient, the second one is more pleasant to the eye. I'd like your comments on my ideas, maybe someone even has a better approach in mind?
[Edit] Reasonal
There are two reasons i am searching for a solution like this:
On the one hand you should try to handle errors before they arise by using the type system. The aforementioned user is of course the designer of the next layer in the system (ie me). By working on the pure tree representation some kinds of bugs won't be able to happen. All changes to the tree in the file should be in one place. That should make reasoning easier.
On the other hand i could just implement something like insert :: FilePath -> Key -> Value -> IO () and be done with it. But then i'll lose a very nice trait that comes free when i keep a (kind of a) log by updating the tree in place. Transactions (ie merging of several inserts) are just a matter of working on the same tree in memory and writing just the differences back to the file.
I think that the package Data.Generic.Diff may do exactly what you wanted. It references somebody's thesis for the idea of how it works.
I am very new at Haskell so I won't be showing code, but hopefully my explanation may help for a solution.
First, why not just expose only the MemTree to the user, since that is what they will update, and the FileTree can be kept completely hidden. That way, later, if you want to change this to be going to a database, for example, the user doesn't see any difference.
So, since the FileTree is hidden, why not just read it in when you are going to update, then you have the offsets, so do the update, and close the file again.
One problem with keeping the offsets is that it prevents another program from making any changes to the file, and in your case that may be fine, but I think as a general rule it is a bad design.
The main change, that I see, is that the MemTree shouldn't be lazy, since the file won't be staying open.
What Unix program generates "diff"s between text files (or
INSERT/UPDATE/DELETEs for databases) in such a way that the order that the "diff"s are applied in is irrelevant, and the result is the same
regardless of order.
Etherpad used to do something like this.
Example (for a given document or database):
% Adam makes a change X, then Bob makes a change Y, then Adam makes
another change Z.
% However, because of network latency, Adam sees the changes in this
order: XZY, while Bob sees them in this order: YXZ.
% However, the code/changes are written so that XYZ and YXZ yield the
same result.
Note: ideally, this can be done without having to do X/Y/Z inverse at any
point.
I have read Operational Transformation library?
but I'm not sure this really does what I want.
Git (or any smart version control system) will provide this functionality.